Les conteneurs



Les conteneurs sont la notion qui a fait connaître et qui a permis de genéraliser l'utilisation de la STL.
Il s'agit d'un ensemble d'implémentations d'objets de stockage, avec les opérations de bases que l'on peut effectuer dessus.
dessus.
 
Les conteneurs sont les objets les plus couramment utilisés en programmation. Nous avons perpétuellement besoin de ce type d'objets. J'avoue qu'avant de connaitre la STL, je passais mon temps à réécrire des listes ou des implémentations de vecteurs, pour chacun des types d'objets que je créais. Un jour j'en ai eu marre et je me suis penché sur les notions de généricité avant de découvrir la STL:

- l'implémentation fonctionne pour n'importe quel type d'objet, du plus simple au plus complexe
- Il n'y a pas de problèmes d'accès aux éléments ( si vous avez déjà créé une liste vous voyez de quoi je parle ... )
- les insertions , suppressions sont gérées de manière efficace
- la gestion des allocations, désallocations est automatique ( avec des pools d'objets libres par exets libres par exemple )

Pour résumer : il n'y a plus de prise de tête!




Les types de conteneurs


Deux grandes classes de conteneurs sont distinguables, auxquelles on peut associer un ensemble de conteneurs dérivés:

- les conteneurs de séquence

Vecteurs, listes, et deques
- les conteneurs associatifs
Sets et multisets, maps et multimaps
- les conteneurs dérivés
Stack, queue et priority_queue







Conteneurs de séquences

Les conteneurs de séquence sont les structures les plus élémentaires, sur lesquelles s'appuient d'ailleurs tous les types plus complexes de conteneurs.

3 types de conteneurs de séquences sont prédéfinis dans la STL, avec chacun leurs spécificités liées aux temps de remplissage et d'accès aux éléments.

Voici une présentation de l'efficacité de chacun des conteneurs, comparée à celle d'un tableau classique en c ( opérateur [] ):

constant ="center">constant
Tableau classique
Vector
list
Deque
Inserer/effacer au début
n/a
linéaire
constant
constant
Inserer/effacer à la fin
n/a
constant
constant
constant
Inserer/effacer n'importe où
n/a
linéaire
constant
linéaire
Accès au premier élémenave;s au premier élément
constant
constant
constant
constant
Accès au dernier élément
constant
constant
constant
constant
Accès n'importe où
constant
constant
linéaire
constant




Le Vecteur




Les vecteurs sont formés d'un seul bloc contigü de mémoire, comme les tableaux en c.

La mémoire est libérée quand l'objet Vecteur est supprimé

A utiliser de préférence lorsque les objets contenus doivent être insérés/supprimés à la fin.

Inefficacité : une copie complête est réalisée lorsque l'on dépasse la mémoire initialement réservée.

Elements requis pour le contenu de type T:
- opérateur ()ockquote> - opérateur () : T();
- constructeur par recopie : T(const T&);
- destructeur : ~T();
- opérateur d'affectation : T& operator=(const T&);


La Liste




La liste est composée d'objets de type precédent-objet-suivant.

Les objets sont alloués à partir d'un pool d'objets préchargés.

La mémoire est libérée quand TOUS les objets contenus sont détruits.

A utiliser de préférence pour des insertions/suppressions aléatoires.

L'opérateur [] n'existe pas.

Inefficacité : très coûteux en mémoire

Elements requis pour le contenu de type uis pour le contenu de type T:
- opérateur () : T();
- constructeur par recopie : T(const T&);
- destructeur : ~T();
- opérateur d'affectation : T& operator=(const T&);
- opérateur &() : T* operator&();
- opérateur de comparaison < : int operator < (const T&, const T&);
- opérateur d'égalité : int operator==(const T&, const T&);


La Double Ended Queue ( Deque )




La deque est composée d'un ensemble de blocs de n élements, accessibles par un bloc "map"

La mémoire est libérée quand la "map" est supprimée

A utiliser de préférence pour les accès au début et à la fin

Inéficacité : l'néficacité : l'opérateur [] est relativement lent ( temps linéaire )

Elements requis pour le contenu de type T:
- opérateur () : T();
- constructeur par recopie : T(const T&);
- destructeur : ~T();
- opérateur d'affectation : T& operator=(const T&);



Conteneurs associatifs




Les conteneurs associatifs sont des conteneurs qui fonctionnent à l'aide de paires clé/élément

L'aspect principal à retenir est que ces conteneurs sont triés ( de par leur nature ) et qu'ils permettent ainsi d'optimiser certaines opérations

4 types de conteneurs associatifs sont définis:
- le set ( l'ensemble ) : chaque élément est sa propre clé et doit donc être unique.
- le multiset, qui est l'équivalent d'un l'équivalent d'un set, mais permettant les doublons
- la map : chaque élément est associé à une clé ( c'est épatant non! ).
- la multimap, équivalente à la map, mais qui permet plusieurs éléments pour une même clé


Un problème de taille intervient dans l'utilisation des multi-machin : l'association clé/valeur n'étant pas bijective ( plusieurs éléments pour une même clé ), la plupart des algorithmes génériques ne pourront pas fonctionner correctement. A utiliser avec précaution...



Conteneurs dérivés



Les conteneurs associatifs sont des conteneurs spéciaux, qui prennent en paramêtre un type de conteneur standard, comme par exemple stack <Vector<int> >

Il s'agit tout simplement d'interfaces spéciales sur les conteneurs standards, qui permettent de simuler un comportement différent.

3 types de conteneurs sont ainsi définis:

- la stack ( pile )

La pile offre simplement la possibilité d'ajouter et supprimer à la fin.
Le plus efficace est donc de l'utiliser avec un vecteur, mais elle peut aussi être utilisée avec la deque et la liste ( qui serait un très iste ( qui serait un très mauvais choix! )
Paramêtre
Description
Valeur par défaut
T
type de l'objet stocké
Séquence
type de conteneur utilisé
dequeue<T>


- la queue ( file )

Permet d'ajouter à la fin et de retirer au début
A utiliser avec la deque ou la liste. Le vecteur fonctionne, mais attention les performances!
Paramêtre
Description
Valeur par défaut
T
type de l'objet stocké
Séquence
type de conteneur utilisé
deque<T>


- la priority-queue ( file avec priorité )

Rien à dire, le nom est explicite
La déclaration peut prendre en paramêtre une fonction de comparaison pour les priorités
A utiliser avec un vecteur ou a la limite avec une deque si la taille est très variable. La liste est inutilisable car l'opérateur [] doit être défini

Paramêtre
enter">Paramêtre
Description
Valeur par défaut
T
type de l'objet stocké
Séquence
type de conteneur utilisé
Vector<T>
Compare
fonction de comparaison
less<T>

<< Précédent
Index
suivant >>