Considere o seguinte trecho:
#include <array>
int main() {
using huge_type = std::array<char, 20*1024*1024>;
huge_type t;
}
Obviamente, ele travaria na maioria das plataformas, porque o tamanho da pilha padrão geralmente é inferior a 20 MB.
Agora considere o seguinte código:
#include <array>
#include <vector>
int main() {
using huge_type = std::array<char, 20*1024*1024>;
std::vector<huge_type> v(1);
}
Surpreendentemente, ele também trava! O traceback (com uma das versões recentes do libstdc ++) leva ao include/bits/stl_uninitialized.h
arquivo, onde podemos ver as seguintes linhas:
typedef typename iterator_traits<_ForwardIterator>::value_type _ValueType;
std::fill(__first, __last, _ValueType());
O vector
construtor de redimensionamento deve inicializar os elementos por padrão, e é assim que ele é implementado. Obviamente, _ValueType()
falhas temporárias na pilha.
A questão é se é uma implementação em conformidade. Se sim, na verdade significa que o uso de um vetor de grandes tipos é bastante limitado, não é?
std::allocator
for usado.Respostas:
Não há limite para a quantidade de armazenamento automático que qualquer API padrão usa.
Todos eles podem exigir 12 terabytes de espaço na pilha.
No entanto, essa API requer apenas
Cpp17DefaultInsertable
e sua implementação cria uma instância extra sobre o que é exigido pelo construtor. A menos que esteja atrasado para detectar que o objeto é trivialmente copiável e copiável, essa implementação parece ilegal.fonte
std::allocator
for usado. Não sei ao certo por que esse caso especial é apresentado em primeiro lugar.std::fill
para tipos triviais, que depois usammemcpy
os bytes em locais, o que é potencialmente muito mais rápido do que construir muitos objetos individuais em um loop. Acredito que a implementação libstdc ++ esteja em conformidade, mas causar um estouro de pilha para objetos grandes é um erro de Qualidade de Implementação (QoI). Eu relatei como gcc.gnu.org/PR94540 e o corrigirei.Eu discuto a suposição de "a maioria". Como a memória do objeto enorme nunca é usada, o compilador pode ignorá-lo completamente e nunca alocar a memória; nesse caso, não haveria falha.
O padrão C ++ não limita o uso da pilha, nem reconhece a existência de uma pilha. Então, sim, está em conformidade com o padrão. Mas pode-se considerar que este é um problema de qualidade de implementação.
Esse parece ser o caso do libstdc ++. A falha não foi reproduzida com libc ++ (usando clang), portanto, parece que isso não é uma limitação na linguagem, mas apenas nessa implementação específica.
fonte
Não sou advogado de idiomas nem especialista em C ++, mas o cppreference.com diz:
Talvez eu esteja entendendo mal "inserção padrão", mas eu esperaria:
ser equivalente a
A última versão não deve criar uma cópia de pilha, mas construir um tipo enorme diretamente na memória dinâmica do vetor.
Não posso dizer com autoridade que o que você está vendo não é compatível, mas certamente não é o que eu esperaria de uma implementação de qualidade.
fonte
std::allocator
, portanto, não deve haver diferença observável entre inserir diretamente na memória de vetores e criar uma cópia intermediária.emplace_back
mas não apenas para criar um vetor. O que significa que você pode ter,vector<mutex> v(1)
mas não.vector<mutex> v; v.emplace_back();
Para algo comohuge_type
você ainda pode ter uma alocação e mover a operação mais com a segunda versão. Nem deve criar objetos temporários.vector::vector(size_type, Allocator const&)
requer (Cpp17) DefaultInsertable