Desde a
- ambos são recipientes de memória contíguos;
- Em termos de recursos, o deque tem quase tudo que o vetor tem, mas muito mais, já que é mais eficiente para inserir na frente.
Por Whould ninguém preferem std::vector
a std::deque
?
Desde a
Por Whould ninguém preferem std::vector
a std::deque
?
Respostas:
Os elementos em a nãodeque
são contíguos na memória; elementos têm a garantia de ser. Portanto, se você precisa interagir com uma biblioteca C simples que precisa de matrizes contíguas, ou se você se preocupa (muito) com a localidade espacial, talvez prefira . Além disso, como há alguma contabilidade extra, outras operações são provavelmente (ligeiramente) mais caras do que suas operações equivalentes . Por outro lado, o uso de muitas / grandes instâncias de pode levar à fragmentação desnecessária do heap (desacelerando as chamadas para ).vector
vector
vector
vector
new
Além disso, conforme apontado em outro lugar no StackOverflow , há mais boas discussões aqui: http://www.gotw.ca/gotw/054.htm .
Para saber a diferença, é preciso saber como deque
geralmente é implementado. A memória é alocada em blocos de tamanhos iguais e eles são encadeados (como uma matriz ou possivelmente um vetor).
Portanto, para encontrar o enésimo elemento, você encontra o bloco apropriado e acessa o elemento dentro dele. Este é um tempo constante, porque é sempre exatamente 2 pesquisas, mas ainda é mais do que o vetor.
vector
também funciona bem com APIs que desejam um buffer contíguo porque são APIs C ou são mais versáteis ao serem capazes de pegar um ponteiro e um comprimento. (Assim, você pode ter um vetor embaixo ou um array regular e chamar a API do seu bloco de memória).
Onde deque
tem suas maiores vantagens são:
O segundo deles é menos conhecido, mas para tamanhos de coleção muito grandes:
Quando eu estava lidando com grandes coleções no passado e mudei de um modelo contíguo para um modelo de bloco, fomos capazes de armazenar uma coleção cerca de 5 vezes maior antes de ficar sem memória em um sistema de 32 bits. Isso ocorre em parte porque, ao realocar, ele realmente precisava armazenar o bloco antigo e também o novo antes de copiar os elementos.
Tendo dito tudo isso, você pode ter problemas com std::deque
sistemas que usam alocação de memória "otimista". Embora suas tentativas de solicitar um tamanho de buffer grande para uma realocação de a vector
provavelmente sejam rejeitadas em algum ponto com a bad_alloc
, a natureza otimista do alocador provavelmente sempre concederá a solicitação de um buffer menor solicitado por a deque
e isso provavelmente causará o sistema operacional para matar um processo para tentar adquirir alguma memória. Qualquer que seja escolhido pode não ser muito agradável.
As soluções alternativas nesse caso são definir sinalizadores no nível do sistema para substituir a alocação otimista (nem sempre viável) ou gerenciar a memória um pouco mais manualmente, por exemplo, usando seu próprio alocador que verifica o uso de memória ou similar. Obviamente não é o ideal. (O que pode responder à sua pergunta quanto à preferência pelo vetor ...)
Eu implementei vetor e deque várias vezes. deque é muito mais complicado do ponto de vista da implementação. Essa complicação se traduz em mais código e código mais complexo. Portanto, você normalmente verá um tamanho de código ao escolher deque em vez de vetor. Você também pode experimentar um pequeno golpe de velocidade se seu código usar apenas as coisas em que o vetor se destaca (ou seja, push_back).
Se você precisa de uma fila dupla, deque é o vencedor. Mas se você estiver fazendo a maioria das inserções e apagamentos no verso, o vetor será o vencedor claro. Quando você não tiver certeza, declare seu contêiner com um typedef (para que seja fácil alternar para frente e para trás) e meça.
vector
.) Eu escrevi uma implementação vinculada a seguir em minha resposta . Pode ser tão rápido quanto um, vector
mas muito mais amplamente aplicável (por exemplo, ao criar uma fila rápida).
std::deque
não tem memória contínua garantida - e geralmente é um pouco mais lento para acesso indexado. Um deque é tipicamente implementado como uma "lista de vetores".
De acordo com http://www.cplusplus.com/reference/stl/deque/ , "ao contrário dos vetores, não é garantido que os deques tenham todos os seus elementos em locais de armazenamento contíguos, eliminando assim a possibilidade de acesso seguro através da aritmética de ponteiros."
Deques são um pouco mais complicados, em parte porque eles não têm necessariamente um layout de memória contíguo. Se você precisar desse recurso, não deve usar um deque.
(Anteriormente, minha resposta levantou uma falta de padronização (da mesma fonte acima, "deques pode ser implementado por bibliotecas específicas de maneiras diferentes"), mas isso na verdade se aplica a praticamente qualquer tipo de dados de biblioteca padrão.)
std::deque
não é menos padronizado do que std::vector
. Não acredito que os requisitos de complexidade para std::deque
possam ser atendidos com armazenamento contíguo.
deque
não podem ser atendidos com armazenamento contíguo?
deque
, ou seja, que a inserção nas extremidades não deve invalidar os referenciados aos elementos existentes. Este requisito implica memória descontínua.
Acho boa ideia fazer teste de desempenho de cada case. E tome a decisão confiando nestes testes.
Eu prefiro do std::deque
que std::vector
na maioria dos casos.
vector
. Podemos inferir que porque não é um corolário. Dizer que você prefere deque
, por razões desconhecidas, a partir de testes não especificados, não é uma resposta.
Você não preferiria que o vetor deque de acordo com os resultados do teste (com a fonte).
Claro, você deve testar em seu aplicativo / ambiente, mas em resumo:
Mais algumas reflexões e uma nota a considerar circular_buffer.
Por um lado, o vetor é freqüentemente muito mais rápido do que o deque. Se você realmente não precisa de todos os recursos do deque, use um vetor.
Por outro lado, às vezes você fazer características necessidades que vector não lhe dá, caso em que você deve usar um deque. Por exemplo, eu desafio qualquer um a tentar reescrever esse código , sem usar um deque e sem alterar enormemente o algoritmo.
push_back
e pop_back
, deque<int>
é sempre pelo menos 20% mais rápido que vector<int>
nos meus testes (gcc com O3). Acho que é por isso que deque
é a escolha padrão para coisas como std::stack
...
Observe que a memória vetorial é realocada à medida que o array cresce. Se você tiver ponteiros para elementos do vetor, eles se tornarão inválidos.
Além disso, se você apagar um elemento, os iteradores se tornam inválidos (mas não "para (auto ...)").
Editar: mudou 'deque' para 'vetor'
std::deque
tem um tamanho de bloco máximo muito pequeno (~ 16 bytes, se bem me lembro; talvez 32) e, como tal, não funciona muito bem para aplicativos realistas. Adeque<T>
wheresizeof(T) > 8
(ou 16? É um número pequeno) tem aproximadamente as mesmas características de desempenho que avector<T*>
, onde cada elemento é alocado dinamicamente. Outras implementações têm tamanhos máximos de bloco diferentes, portanto, é difícil escrever código que tenha relativamente as mesmas características de desempenho em plataformas diferentesdeque
.