Il y a une image bien connue (antisèche) intitulée « Choice conteneur C++ ». C’est un diagramme de choisir le meilleur récipient pour l’usage voulu.
Quelqu'un sait-il s’il existe déjà une version C ++11 de celui-ci ?
Il s’agit de l’antérieure :
Il y a une image bien connue (antisèche) intitulée « Choice conteneur C++ ». C’est un diagramme de choisir le meilleur récipient pour l’usage voulu.
Quelqu'un sait-il s’il existe déjà une version C ++11 de celui-ci ?
Il s’agit de l’antérieure :
Pas que je sache, cependant, il peut être fait sous forme de texte, je suppose. Aussi, le tableau est légèrement en dehors, parce qu' list
n'est pas un bon récipient en général, et ni est - forward_list
; les deux listes sont très emballages spécialisés pour des applications de niche.
Pour construire un tel graphique, vous avez juste besoin de deux simples lignes directrices:
Se soucier de la performance est généralement inutile au premier abord, le big O seulement vraiment le coup lorsque vous commencez à la manipulation de quelques milliers (ou plus) d'éléments.
Il y a deux grandes catégories de conteneurs:
find
fonctionnementet puis vous pouvez créer plusieurs cartes sur le dessus d'eux: stack
, queue
, priority_queue
. Je vais laisser les cartes ici, ils sont assez spécialisés pour être reconnaissable.
Question 1: Associatif ?
Question 1.1: Commandé ?
unordered_
conteneur, sinon utiliser son traditionnel commandé homologue.Question 1.2: Clé Distinct ?
map
, sinon utiliser un set
Question 1.3: Les Doublons ?
multi
, sinon, ne pas.Exemple:
Supposons que j'ai plusieurs personnes avec un ID unique associée, et je voudrais récupérer une personne données à partir de son ID aussi simplement que possible.
Je veux un find
la fonction, donc un conteneur associatif
1.1. Je me moque de l'ordre, ainsi que l' unordered_
conteneur
1.2. Mon key (ID) est distincte de la valeur, il est associé avec, donc, une map
1.3. L'ID est unique, donc pas de duplicata doit ramper dans.
La réponse finale est: std::unordered_map<ID, PersonData>
.
Question 2: la Mémoire stable ?
list
Question 2.1: Qui ?
list
; forward_list
n'est utile que pour la moindre empreinte mémoire.Question 3: Dynamiquement la taille ?
{ ... }
de la syntaxe), puis utiliser une array
. Il remplace la traditionnelle C-tableau, mais avec des fonctions pratiques.Question 4: Double-clos ?
deque
, sinon utiliser un vector
.Il est à noter que, par défaut, sauf si vous avez besoin d'un conteneur associatif, votre choix sera un vector
.
J'aime Matthieu réponse, mais je vais reformuler l'organigramme comme ceci:
Par défaut, si vous avez besoin d'un conteneur de trucs, utilisez std::vector
. Ainsi, tous les autres conteneur n'est justifiée par la fourniture de certaines fonctionnalités alternative à l' std::vector
.
std::vector
exige que son contenu sont déplacer constructible, car il doit être capable de mélanger les éléments autour. Ce n'est pas un fardeau terrible à placer sur le contenu (à noter que les constructeurs par défaut sont pas nécessaires, grâce à l' emplace
et ainsi de suite). Cependant, la plupart des autres contenants ne nécessitent pas toute particulière constructeur (encore une fois, grâce à l' emplace
). Donc, si vous avez un objet où vous absolument ne peut pas mettre en œuvre un constructeur de déplacement, alors vous aurez à choisir autre chose.
Un std::deque
serait le remplacement général, ayant de nombreuses propriétés de l' std::vector
, mais vous ne pouvez insérer qu'aux extrémités de la deque. Des Inserts au milieu nécessitent le déplacement. Un std::list
n'impose aucune exigence sur son contenu.
std::vector<bool>
... n'est pas. Eh bien, c'est du standard. Mais ce n'est pas un vector
dans le sens habituel du terme, comme des activités qui std::vector
permet en principe interdit. Et le plus certainement ne contient pas d' bool
s.
Par conséquent, si vous avez besoin d'une réelle vector
comportement à partir d'un conteneur de bool
s, vous n'allez pas à l'obtenir à partir d' std::vector<bool>
. De sorte que vous aurez à faire avec un std::deque<bool>
.
Si vous avez besoin de trouver des éléments dans un conteneur, et le tag de recherche ne peut pas simplement être un indice, alors vous pourriez avoir besoin d'abandonner std::vector
en faveur de l' set
et map
. Remarque le mot-clé "mai"; une triés std::vector
est parfois une solution de rechange raisonnable. Ou Boost.Conteneur flat_set/map
, qui met en œuvre triés std::vector
.
Il y a maintenant quatre variantes de ces, chacune avec leurs propres besoins.
map
lors de la recherche de la balise n'est pas la même chose que le point que vous êtes à la recherche pour elle-même. Sinon, utiliser un set
.unordered
quand vous avez beaucoup d'éléments dans le conteneur et la recherche de la performance doit absolument être O(1)
, plutôt que d' O(logn)
.multi
si vous avez besoin de plusieurs éléments ont le même tag de recherche.Si vous avez besoin d'un conteneur d'éléments de toujours être triés sur la base de la comparaison opération, vous pouvez utiliser un set
. Ou un multi_set
si vous avez besoin de plusieurs éléments ont la même valeur.
Ou vous pouvez utiliser un triées std::vector
, mais vous devrez garder de tri.
Lorsque les itérateurs et les références sont invalidés est parfois un sujet de préoccupation. Si vous avez besoin d'une liste d'éléments, tels que vous avez des itérateurs/pointeurs vers ces articles dans divers autres lieux, alors std::vector
s'approche à l'invalidation peut ne pas être approprié. Tout d'insertion opération peut entraîner l'invalidation, en fonction de la taille et de la capacité.
std::list
offre une garantie solide: un itérateur et de ses références/pointeurs ne sont invalidés lorsque l'élément est supprimé du conteneur. std::forward_list
est-il si la mémoire est une source de grave préoccupation.
Si c'est trop fort une garantie, std::deque
offre une plus faible mais utile de garantie. L'Invalidation des résultats de insertions dans le milieu, mais les insertions à la tête ou de queue, ne provoque que l'invalidation des itérateurs, pas des pointeurs/références à des éléments dans le conteneur.
std::vector
seulement fournit à bas prix d'insertion à la fin (et même alors, il devient coûteux si vous souffler la capacité).
std::list
est coûteux en termes de performances (chaque nouvel élément inséré des coûts de l'allocation de mémoire), mais c'est cohérent. Il offre également la parfois indispensable capacité à mélanger des éléments autour de pratiquement aucune incidence sur les performances, ainsi que pour échanger des objets avec d'autres std::list
des conteneurs de même type, sans perte de performance. Si vous avez besoin de mélanger les choses autour d' un lot, utilisez std::list
.
std::deque
fournit à constante de temps de l'insertion/retrait à la tête et la queue, mais l'insertion dans le milieu peut être assez cher. Donc, si vous avez besoin d'ajouter/enlever des choses de l'avant et à l'arrière, std::deque
pourrait être ce dont vous avez besoin.
Il convient de noter que, grâce à la sémantique de déplacement, std::vector
d'insertion de la performance ne peut pas être aussi mauvais qu'il l'habitude d'être. Certaines implémentations mis en place un formulaire de déplacer la sémantique en fonction de l'élément de la copie (le soi-disant "swaptimization"), mais maintenant que le déménagement est une partie de la langue, il est mandaté par le standard.
std::array
est une amende conteneur si vous voulez le moins possible des allocations dynamiques. C'est juste un wrapper autour d'une C-tableau; ce qui signifie que sa taille doit être connu au moment de la compilation. Si vous pouvez vivre avec ça, puis utilisez std::array
.
Cela étant dit, l'utilisation d' std::vector
et reserve
ing une taille aussi bien délimité std::vector
. De cette façon, la taille réelle peut varier, et vous n'aurez qu'une seule allocation de mémoire (à moins que vous souffler la capacité).
Voici un tour rapide, mais il a probablement besoin de travailler
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
Vous remarquerez peut-être que cela diffère sauvagement à partir du C++03 version, principalement en raison du fait que je n'aime vraiment pas liée nœuds. Le nœud lié conteneurs peuvent généralement être battu dans les performances par un non-lié conteneur, sauf dans quelques rares situations. Si vous ne savez pas ce que ces situations sont, et ont accès à stimuler, n'utilisez pas lié nœud de conteneurs. (std::list, std::slist, std::map, std::multimap, std::set, std::multiset). Cette liste se concentre principalement sur les petites et moyennes récipients à paroi, parce que (Un) c'est de 99,99% de ce que nous traitons dans le code, et (B) un Grand nombre d'éléments des algorithmes personnalisés, pas des récipients différents.
Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.