web-dev-qa-db-fra.com

Dans quel scénario dois-je utiliser un conteneur STL particulier?

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.

170
Daniel Sloof

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:

http://linuxsoftware.co.nz/containerchoice.png

Créé par David Moore et sous licence CC BY-SA 3.0

308
zdan

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:

enter image description here

172
Mikael Persson

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.

37
David Thornley

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.

10
Mark Krenitsky

J'ai repensé l'organigramme pour avoir 3 propriétés:

  1. Je pense que les conteneurs STL sont divisés en 2 classes principales. Les conteneurs de base et ceux-ci s'appuient sur les conteneurs de base pour mettre en œuvre une politique.
  2. Au début, l’organigramme devrait diviser le processus de décision en fonction des situations principales sur lesquelles nous devrions nous prononcer, puis élaborer pour chaque cas.
  3. Certains conteneurs étendus ont la possibilité de choisir différents conteneurs de base comme conteneurs intérieurs. L'organigramme doit prendre en compte les situations dans lesquelles chacun des conteneurs de base peut être utilisé.

L'organigramme:  enter image description here

Plus d'informations fournies dans ce lien .

7
Ebrahim

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.

4
Jonathan Wakely

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.

4
Bids

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 (-:

2
vrdhn

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++

1
John DiFini

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

0
CS Pei