J'ai lu sur les conteneurs STL dans mon livre sur C++, en particulier la section sur la STL et ses conteneurs. Maintenant, je comprends que chacun d’entre eux a ses propres propriétés spécifiques, et je suis sur le point de les mémoriser… Mais ce que je ne comprends pas encore, c’est dans quel scénario chacun d’entre eux est utilisé.
Quelle est l'explication? Exemple de code est de loin préférable.
Cette aide-mémoire fournit un assez bon résumé des différents conteneurs.
Voir l'organigramme en bas comme guide d'utilisation dans différents scénarios d'utilisation:
Créé par David Moore et sous licence CC BY-SA 3.0
Voici un organigramme inspiré de la version de David Moore (voir ci-dessus) que j'ai créée et qui est à jour (principalement) avec le nouveau standard (C++ 11). Ce n’est que mon point de vue personnel, ce n’est pas indiscutable, mais j’ai pensé que cela pourrait être utile pour cette discussion:
Réponse simple: utilisez std::vector
pour tout sauf si vous avez une raison réelle de faire autrement.
Lorsque vous trouvez un cas où vous pensez "Gee, std::vector
ne fonctionne pas bien ici à cause de X", utilisez X.
Regardez Effective STL de Scott Meyers. C'est bon pour expliquer comment utiliser le STL.
Si vous souhaitez stocker un nombre d'objets déterminé/indéterminé et que vous ne supprimez aucun objet, vous devez choisir un vecteur. C'est le remplacement par défaut pour un tableau C, et cela fonctionne comme un, mais ne déborde pas. Vous pouvez également définir sa taille à l’avance avec reserve ().
Si vous souhaitez stocker un nombre indéterminé d'objets, mais que vous les ajouterez et les supprimerez, vous souhaiterez probablement une liste ... car vous pouvez supprimer un élément sans déplacer les éléments suivants, contrairement à vector. Cependant, cela prend plus de mémoire qu'un vecteur et vous ne pouvez pas accéder séquentiellement à un élément.
Si vous voulez prendre un tas d'éléments et ne trouver que les valeurs uniques de ces éléments, les lire tous dans un ensemble le fera et les triera également pour vous.
Si vous avez beaucoup de paires clé-valeur et que vous souhaitez les trier par clé, une carte est utile ... mais elle ne contiendra qu'une valeur par clé. Si vous avez besoin de plus d'une valeur par clé, vous pouvez utiliser un vecteur/une liste comme valeur sur la carte ou utiliser une carte multiple.
Ce n'est pas dans la STL, mais dans la mise à jour TR1 de la STL: si vous avez plusieurs paires clé-valeur que vous allez rechercher par clé et que vous ne vous souciez pas de leur ordre, vous pouvez voulez utiliser un hash - qui est tr1 :: unordered_map. Je l'ai utilisé avec Visual C++ 7.1, où il s'appelait stdext :: hash_map. Il a une recherche de O(1) au lieu d'une recherche de O (log n) pour la carte.
J'ai repensé l'organigramme pour avoir 3 propriétés:
Plus d'informations fournies dans ce lien .
Un point important mentionné brièvement jusqu'à présent est que si vous avez besoin de mémoire contiguë (comme le donne un tableau C), vous ne pouvez utiliser que vector
, array
ou string
.
Utilisez array
si la taille est connue au moment de la compilation.
Utilisez string
si vous n’avez besoin que de travailler avec des types de caractères et si vous avez besoin d’une chaîne, pas seulement d’un conteneur à usage général.
Utilisez vector
dans tous les autres cas (vector
devrait néanmoins être le choix par défaut du conteneur dans la plupart des cas).
Avec ces trois éléments, vous pouvez utiliser la fonction membre data()
pour obtenir un pointeur sur le premier élément du conteneur.
Tout dépend de ce que vous voulez stocker et de ce que vous voulez faire avec le conteneur. Voici quelques exemples (non exhaustifs) des classes de conteneur que j'ai tendance à utiliser le plus souvent:
vector
: mise en page compacte avec peu ou pas de surcharge de mémoire par objet contenu. Efficace pour itérer. L'ajout, l'insertion et l'effacement peuvent être coûteux, en particulier pour les objets complexes. Pas cher de trouver un objet contenu par index, par ex. myVector [10]. Utilisez l’endroit où vous auriez utilisé un tableau en C. Bon où vous avez beaucoup d’objets simples (par exemple, int). N'oubliez pas d'utiliser reserve()
avant d'ajouter de nombreux objets au conteneur.
list
: Petite surcharge de mémoire par objet contenu. Efficace pour itérer. Ajouter, insérer et effacer sont bon marché. Utilisez l'endroit où vous auriez utilisé une liste chaînée en C.
set
(et multiset
): surcharge de mémoire importante par objet contenu. Utilisez l’endroit où vous devez savoir rapidement si ce conteneur contient un objet donné, ou bien fusionner les conteneurs.
map
(et multimap
): surcharge de mémoire importante par objet contenu. Utilisez l’emplacement où vous souhaitez stocker les paires clé-valeur et recherchez rapidement les valeurs par clé.
L’organigramme figurant sur le aide-mémoire suggéré par zdan fournit un guide plus exhaustif.
L’une des leçons que j’ai apprises est la suivante: Essayez de l’emballer dans un cours, car changer le type de conteneur un beau jour peut donner de grandes surprises.
class CollectionOfFoo {
Collection<Foo*> foos;
.. delegate methods specifically
}
Cela ne coûte pas cher au début, et vous fait gagner du temps en débogage lorsque vous voulez interrompre chaque fois que quelqu'un exécute l'opération x sur cette structure.
Venir à la sélection de la structure de données parfaite pour un travail:
Chaque structure de données fournit certaines opérations pouvant varier en complexité temporelle:
O (1), O (lg N), O (N), etc.
Vous devez essentiellement deviner, sur quelles opérations seront effectuées le plus, et utiliser une structure de données qui a cette opération sous la forme O (1).
Simple, n'est-ce pas (-:
J'ai développé __ (organigramme fantastique) de Mikael Persson . J'ai ajouté des catégories de conteneurs, le conteneur de tableaux et des notes. Si vous souhaitez utiliser votre propre copie, ici est le dessin Google. Merci, Mikael d’avoir préparé le terrain! Sélecteur de conteneurs C++
J'ai répondu à cela dans une autre question qui est marquée comme dup de celle-ci. Mais j'estime qu'il est agréable de se référer à quelques bons articles concernant la décision de choisir un conteneur standard.
Comme @David Thornley a répondu, std :: vector est la voie à suivre s’il n’ya pas d’autres besoins spéciaux. C'est le conseil donné par le créateur de C++, Bjarne Stroustrup dans un blog de 2014.
Voici le lien pour l'article https://isocpp.org/blog/2014/06/stroustrup-lists
et cite de celui-là,
Et, oui, ma recommandation est d'utiliser std :: vector par défaut.
Dans les commentaires, l'utilisateur @NathanOliver fournit également un autre bon blog, qui présente des mesures plus concrètes. https://baptiste-wicht.com/posts/2012/12/cpp-benchmark-vector-list-deque.html .