Há uma imagem bem conhecida (folha de dicas) chamada "Escolha do container C ++". É um fluxograma para escolher o melhor recipiente para o uso desejado.
Alguém sabe se já existe uma versão em C ++ 11?
Este é o anterior:

Há uma imagem bem conhecida (folha de dicas) chamada "Escolha do container C ++". É um fluxograma para escolher o melhor recipiente para o uso desejado.
Alguém sabe se já existe uma versão em C ++ 11?
Este é o anterior:

Respostas:
Não que eu saiba, no entanto, isso pode ser feito textualmente, eu acho. Além disso, o gráfico está um pouco desligado, porque listgeralmente não é um contêiner tão bom nem o é forward_list. Ambas as listas são contêineres muito especializados para aplicações de nicho.
Para criar esse gráfico, você só precisa de duas diretrizes simples:
Preocupar-se com o desempenho é geralmente inútil no início. As grandes considerações de O realmente surgem quando você começa a manusear alguns milhares (ou mais) de itens.
Existem duas grandes categorias de contêineres:
findoperaçãoe então você pode construir vários adaptadores em cima deles: stack, queue, priority_queue. Deixarei os adaptadores aqui fora, eles são suficientemente especializados para serem reconhecidos.
Pergunta 1: associativo ?
Pergunta 1.1: Encomenda ?
unordered_contêiner; caso contrário, use sua contraparte tradicional solicitada.Pergunta 1.2: Chave separada ?
map, caso contrário, use umsetPergunta 1.3: Duplicatas ?
multi, caso contrário não.Exemplo:
Suponha que eu tenha várias pessoas com um ID exclusivo associado a elas e gostaria de recuperar os dados de uma pessoa a partir dele, da maneira mais simples possível.
Eu quero uma findfunção, portanto, um contêiner associativo
1.1 Eu não poderia me importar menos com a ordem, portanto, um unordered_contêiner
1.2 Minha chave (ID) é separada do valor ao qual está associada, portanto, ummap
1.3 O ID é único, portanto, nenhuma duplicata deve aparecer.
A resposta final é: std::unordered_map<ID, PersonData>.
Pergunta 2: Memória estável ?
listPergunta 2.1: Qual ?
list; a forward_listé útil apenas para menos espaço ocupado na memória.Pergunta 3: Dimensionado dinamicamente ?
{ ... }sintaxe), use um array. Ele substitui o C-array tradicional, mas por funções convenientes.Pergunta 4: com duas pontas ?
deque; caso contrário, use a vector.Você observará que, por padrão, a menos que precise de um contêiner associativo, sua escolha será a vector. Acontece que também é a recomendação de Sutter e Stroustrup .
arraynão requer um tipo construtível padrão; 2) escolher multies não é tanto sobre duplicidades serem permitidas, mas mais sobre se mantê- las é importante (você pode colocar duplicatas em não multicontêineres, acontece que apenas uma é mantida).
map.find(key)é muito mais palatável do que no std::find(map.begin(), map.end(), [&](decltype(map.front()) p) { return p.first < key; }));entanto, portanto, é importante, semanticamente, que findseja uma função de membro e não a função de <algorithm>. Quanto a O (1) vs O (log n), não afeta a semântica; Vou remover o "eficientemente" do exemplo e substituí-lo por "facilmente".
dequetivesse essa propriedade também?
dequeos elementos são estáveis somente se você pressionar / pop em cada extremidade; se você começar a inserir / apagar no meio, até N / 2 elementos serão embaralhados para preencher a lacuna criada.
Gosto da resposta de Matthieu, mas vou reafirmar o fluxograma da seguinte maneira:
Por padrão, se você precisar de um contêiner de material, use std::vector. Assim, todos os outros contêineres são justificados apenas fornecendo alguma funcionalidade alternativa a std::vector.
std::vectorrequer que seu conteúdo seja construtível para movimentação, pois precisa ser capaz de embaralhar os itens. Isso não é um fardo terrível para colocar no conteúdo (observe que construtores padrão não são necessários , graças a emplaceoutras coisas). No entanto, a maioria dos outros contêineres não requer nenhum construtor em particular (novamente, graças a emplace). Portanto, se você tem um objeto em que absolutamente não pode implementar um construtor de movimento, precisará escolher outra coisa.
A std::dequeseria a substituição geral, com muitas das propriedades de std::vector, mas você só pode inserir nas duas extremidades do deque. Inserções no meio exigem movimento. A std::listnão exige requisitos em seu conteúdo.
std::vector<bool>não é. Bem, é padrão. Mas não é um vectorno sentido usual, pois as operações que std::vectornormalmente permitem são proibidas. E certamente não contém bools .
Portanto, se você precisar de um vectorcomportamento real de um contêiner de bools, não será possível obtê-lo std::vector<bool>. Então você terá que fazer o devido com um std::deque<bool>.
Se você precisar encontrar elementos em um contêiner, e a tag de pesquisa não puder ser apenas um índice, poderá ser necessário abandonar a std::vectorfavor de sete map. Observe a palavra-chave " may "; um ordenado std::vectoràs vezes é uma alternativa razoável. Ou Boost.Container's flat_set/map, que implementa uma classificação std::vector.
Agora existem quatro variações delas, cada uma com suas próprias necessidades.
mapquando a tag de pesquisa não for a mesma coisa que o item que você está procurando. Caso contrário, use a set.unorderedquando você tiver muitos itens no contêiner e o desempenho da pesquisa for absolutamente necessário O(1), e não O(logn).multise você precisar de vários itens para ter a mesma tag de pesquisa.Se você precisar que um contêiner de itens seja sempre classificado com base em uma operação de comparação específica, poderá usar a set. Ou a, multi_setse você precisar de vários itens para ter o mesmo valor.
Ou você pode usar uma classificação std::vector, mas terá que mantê-la classificada.
Quando iteradores e referências são invalidados, às vezes é uma preocupação. Se você precisar de uma lista de itens, de modo que tenha iteradores / ponteiros para esses itens em vários outros lugares, std::vectora abordagem da invalidação pode não ser apropriada. Qualquer operação de inserção pode causar invalidação, dependendo do tamanho e capacidade atuais.
std::listoferece uma garantia firme: um iterador e suas referências / indicadores associados só são invalidados quando o próprio item é removido do contêiner. std::forward_listexiste se a memória é uma preocupação séria.
Se essa é uma garantia muito forte, std::dequeoferece uma garantia mais fraca, mas útil. A invalidação resulta de inserções no meio, mas inserções na cabeça ou na cauda causam apenas invalidação de iteradores , não ponteiros / referências a itens no contêiner.
std::vector fornece apenas inserção barata no final (e mesmo assim, fica caro se você aumentar a capacidade).
std::listé caro em termos de desempenho (cada item recém-inserido custa uma alocação de memória), mas é consistente . Ele também oferece a capacidade ocasionalmente indispensável de embaralhar itens praticamente sem custo de desempenho, além de trocar itens com outros std::listcontêineres do mesmo tipo sem perda de desempenho. Se você precisar embaralhar bastante as coisas , use std::list.
std::dequefornece inserção / remoção em tempo constante na cabeça e cauda, mas a inserção no meio pode ser bastante cara. Portanto, se você precisar adicionar / remover itens da parte frontal e traseira, std::dequepode ser o que você precisa.
Note-se que, graças à semântica da movimentação, std::vectoro desempenho da inserção pode não ser tão ruim quanto costumava ser. Algumas implementações implementaram uma forma de cópia de itens baseados em semântica de movimentação (a chamada "swaptimization"), mas agora que a movimentação faz parte do idioma, é exigida pelo padrão.
std::arrayé um contêiner fino se você deseja o menor número possível de alocações dinâmicas. É apenas um invólucro em torno de uma matriz C; isso significa que seu tamanho deve ser conhecido em tempo de compilação . Se você pode viver com isso, use std::array.
Dito isto, o uso std::vectore reserveing de um tamanho funcionariam tão bem para um limite std::vector. Dessa forma, o tamanho real pode variar e você recebe apenas uma alocação de memória (a menos que reduza a capacidade).
std::sort, também std::inplace_mergeé interessante colocar facilmente novos elementos (em vez de uma chamada std::lower_bound+ std::vector::insert). É bom aprender sobre flat_sete flat_map!
vector<bool>é vector<char>.
std::allocator<T>não suportar esse alinhamento (e não sei por que não seria), você sempre poderá usar seu próprio alocador personalizado.
std::vector::resizetem uma sobrecarga que não leva um valor (apenas assume o novo tamanho; quaisquer novos elementos serão construídos no local por padrão). Além disso, por que os compiladores não conseguem alinhar corretamente os parâmetros de valor, mesmo quando são declarados com esse alinhamento?
bitsetpara bool se você sabe o tamanho de antecedência en.cppreference.com/w/cpp/utility/bitset
Aqui está a versão C ++ 11 do fluxograma acima. [publicado originalmente sem atribuição ao autor original, Mikael Persson ]

Aqui está uma rápida rotação, embora provavelmente precise de trabalho
Should the container let you manage the order of the elements?
Yes:
Will the container contain always exactly the same number of elements?
Yes:
Does the container need a fast move operator?
Yes: std::vector
No: std::array
No:
Do you absolutely need stable iterators? (be certain!)
Yes: boost::stable_vector (as a last case fallback, std::list)
No:
Do inserts happen only at the ends?
Yes: std::deque
No: std::vector
No:
Are keys associated with Values?
Yes:
Do the keys need to be sorted?
Yes:
Are there more than one value per key?
Yes: boost::flat_map (as a last case fallback, std::map)
No: boost::flat_multimap (as a last case fallback, std::map)
No:
Are there more than one value per key?
Yes: std::unordered_multimap
No: std::unordered_map
No:
Are elements read then removed in a certain order?
Yes:
Order is:
Ordered by element: std::priority_queue
First in First out: std::queue
First in Last out: std::stack
Other: Custom based on std::vector?????
No:
Should the elements be sorted by value?
Yes: boost::flat_set
No: std::vector
Você pode notar que isso difere bastante da versão C ++ 03, principalmente devido ao fato de eu realmente não gostar de nós vinculados. Os contêineres do nó vinculado geralmente podem ser superados no desempenho por um contêiner não vinculado, exceto em algumas situações raras. Se você não souber quais são essas situações e tiver acesso a melhorias, não use contêineres de nós vinculados. (std :: list, std :: slist, std :: map, std :: multimap, std :: set, std :: multiset). Essa lista se concentra principalmente em contêineres pequenos e médios, porque (A) é 99,99% do que lidamos com código e (B) Um grande número de elementos precisa de algoritmos personalizados, não de contêineres diferentes.