<section id="2.7"><title>Intoduction à la classe vector</title>
<paragraph>Avec les <b>string</b> nous avons pu remplir une chaîne de caractères sans savoir de quelle taille nous allions avoir besoin. Le problème avec la lecture de lignes dans des objets <b>string</b> individuels est que vous ne savez pas à l'avance de combien d'objets vous allez avoir besoin - vous ne le savez qu'après avoir lu le fichier en entier. Pour résoudre ce problème, nous avons besoin d'une sorte de support qui va automatiquement s'agrandir pour contenir autant d'objets <b>string</b> que nous aurons besoin d'y mettre.</paragraph>
<paragraph>
En fait, pourquoi se limiter à des objets <b>string</b> ?
Il s'avère que ce genre de problème - ne pas connaître le nombre de choses que vous avez lorsque vous écrivez le programme - est fréquent. Et il semble que ce “conteneur” serait beaucoup plus utile s'il pouvait contenir <i>toute sorte d'objet !</i> Heureusement, la bibliothèque standard a une solution toute faite : les classes de conteneurs standards. Les classes de conteneur sont une des forces du standard C++.
</paragraph>
<paragraph>
Il y a souvent une petite confusion entre les conteneurs et les algorithmes dans la bibliothèque standard du C++, et l'entité connue sous le nom de STL. Standard Template Library (Bibliothèque de modèle standards) est le nom qu'Alex Stepanov (qui travaillait alors pour Hewlett-Packard) utilisa lorsqu'il présenta sa bibliothèque au Comité de Standardisation de C++ à la conférence de San Diego, Californie au printemps 1994. Le nom est resté, surtout après que HP ai décidé de la rendre disponible au libre téléchargement.
Entre-temps,le comité l'a intégré dans la bibliothèque standard du C++, source d'un grand nombre de changements. Le développement de la STL continu à la Silicon Graphics (SGI; voir <i>http://www.sgi.com/Technology/STL</i>). Le STL de SGI diverge de la bibliothèque strandard du C++ si un certain nombre de points subtiles. Ainsi, bien que cela soit une populaire idée fausse, la bibliothèque standard du C++ n'inclut pas la STL. Cela peut prêter à confusion du fait que les conteneurs et les algorithmes de la bibliothèque standard du C++ ont la même racine (et souvent les mêmes noms) que la STL de SGI. Dans ce livre, je dirais “bibliothèque standard du C++” ou “conteneurs de la bibliothèque standard,” ou quelque chose de similaire et éviterais le terme “STL.”</paragraph>
<paragraph>
Même si l'implémentation des conteneurs et des algorithmes de la bibliothèque standard du C++ utilisent des concepts avancés et que la couverture de cette dernière prenne deux grands chapitres dans le volume 2 de ce livre, cette bibliothèque peut également être efficace sans en savoir beaucoup à son sujet. Elle est si utile que le plus basique des conteneurs standards, le <b>vector</b>, est introduit dès ce chapitre et utilisé tout au long de ce livre. Vous constaterez que vous pouvez faire une quantité de choses énorme juste en employant les fonctionnalités de base du <b>vector</b> et sans vous inquiéter pour l'implémentation (encore une fois, un but important de la POO).
Puisque vous apprendrez beaucoup plus à ce sujet et sur d'autres conteneurs quand vous atteindrez les chapitres sur la bibliothèque standard dans le volume 2, on pardonnera le fait que les programmes utilisant le <b>vector</b> dans la première partie de ce livre ne soient pas exactement ce qu'un programmeur expérimenté de C++ ferait. Vous trouverez cela dans la plupart des cas, l'utilisation montré ici est suffisante.
</paragraph>
<paragraph>
La classe <b>vector</b> est une <i>classe générique</i>, ce qui signifie qu'elle peut être appliquée efficacement à différents types. Ainsi, on peut créer un vecteur de formes, un vecteur de chats, un vecteur de chaînes de caractères, etc. Fondamentalement, avec une classe générique vous pouvez créer une “classe de n'importe quoi”. Pour dire au compilateur ce avec quoi la classe va travailler (dans ce cas, ce que le <b>vector</b> va contenir), vous mettez le type désiré entre ‘<’ et ‘>’. Ainsi un vecteur de chaînes de caractères se note <b>vector<string></b>. Lorsque vous faites cela, vous obtenez un vecteur personnalisé ne pouvant contenir uniquement que des objets string, et vous aurez un message d'erreur de la part du compilateur si vous essayez d'y mettre autre chose.
</paragraph>
<paragraph>
Puisque le vecteur exprime le concept de “conteneur,” il doit y avoir une manière d'y mettre des objets et d'en enlever. Pour ajouter un élément nouveau à la fin d'un <b>vector</b>, vous utilisez la fonction membre <b>push_back( ).</b> (Rappelez vous que, lorsqu'il s'agit d'une fonction membre, vous utilisez le ‘<b>.</b>’ pour l'appeler à partir d'un objet particulier.) La raison du nom de cette fonction membre qui peut sembler verbeux –<b>push_back( )</b> au lieu de quelque chose de plus simple comme “put”– est qu'il y d'autres conteneurs et fonctions membres pour mettre des éléments dans les conteneurs. Par exemple, il y a une fonction membre <b>insert( )</b> pour mettre quelque chose au milieu d'un conteneur. Le <b>vector</b> supporte cela mais son utilisation est plus compliquée et nous n'avons pas besoin de la découvrir avant le volume 2 de ce livre. Il y a aussi <b>push_front( )</b> (qui n'est pas une fonction membre de la classe <b>vector</b>) pour mettre des objets en tête. Il y a pas mal d'autres fonctions membre de <b>vector</b> et pas mal de conteneurs standards dans le bibliothèque standard du C++, mais vous seriez surpris de tout ce que vous pouvez faire en ne connaissant que quelques fonctionnalités simples.
</paragraph>
<paragraph>
Donc vous pouvez mettre des éléments dans un <b>vector</b> avec <b>push_back( )</b>, mais comment les récupérer par la suite ? Cette solution est plus intelligente et et élégante – la surcharge d'opérateur est utilisée pour faire ressembler le <v>vector</b> à un <i>tableau</i>. Le tableau (qui sera décrit plus en détail dans le prochain chapitre) est un type de données qui est disponible dans pratiquement tout langage de programmation il devait déjà vous être familier. Les tableaux sont des <i>agrégats</i>, ce qui signifie qu'ils consistent en un nombre d'éléments groupé entre eux. La caractéristique distinctive d'un tableau est que les éléments sont de même taille et sont arrangés pour être l'un après l'autre. Plus important, ces éléments peuvent être sélectionnés par “indexation”, ce qui veut dire que vous pouvez dire “je veux l'élément numéro n” et cet élément sera accessible, en général très rapidement. Bien qu'il y ait des exceptions dans les langages de programmation, l'indexation est normalement réalisé en utilisant les crochets, de cette façon si vous avez un tableau <b>a</b> et que vous voulez accéder au cinquième élément, vous écrivez <b>a[4]</b> (notez que l'indexation commence à zéro).</paragraph>
<paragraph>Cette notation d'indexation très compact et puissante est incorporée dans la classe <b>vector</n> en utilisant la surcharge d'opérateur, tout comme pour ‘<b><<</b>’ et ‘<b>>></b>’ sont incorporés dans iostreams. Encore une fois, nous n'avons pas besoin de connaître les détails de l'implémentation de la surcharge – cela fera l'objet d'un prochain chapitre – mais c'est utile si vous avez l'impression qu'il y a de la magie dans l'air dans l'utilisation de <b>[ ]</b> avec le vecteur.</paragraph>
<paragraph>Avec cela à l'esprit, vous pouvez maintenant voir un programme utilisant la classe <b>vector</b>. Pour utiliser un <b>vector</b>, vous incluez le fichier d'en-tête <b><vector></b> :</paragraph>
<code langage="cpp">//: C02:Fillvector.cpp
// Copy an entire file into a vector of string
#include <string>
#include <iostream>
#include <fstream>
#include <vector>
using namespace std;
int main() {
vector<string> v;
ifstream in("Fillvector.cpp");
string line;
while(getline(in, line))
v.push_back(line); // Add the line to the end
// Add line numbers:
for(int i = 0; i < v.size(); i++)
cout << i << ": " << v[i] << endl;
} ///:~</code>
<paragraph>Une grande partie de ce programme est similaire au précédent; un fichier est ouvert et les lignes sont lues une par une dans des objets <b>string</b>. Cependant, ces objets <b>string</b> sont <i>poussés</i> à la fin du <b>vecteur v</b>. Une fois la boucle <b>while</b> terminée, le fichier entier réside en mémoire, dans <b>v</b>.</paragraph>
<paragraph>L'étape suivante du programme est ce que l'on appelle une boucle <b>for</b>. Elle est similaire à la boucle <b>while</b> excepté qu'on lui ajoute comme une commande supplémentaire. Après le <b>for</b>, il y a une “expression de contrôle” entre parenthèses, tout comme pour la boucle <b>while</b>. Cependant, cette expression de contrôle est en trois parties : une partie qui initialise, une qui teste si l'on doit sortir de la boucle, et une qui change quelque chose, typiquement pour incrémenter une séquence d'items. Ce programme exhibe une boucle <b>for</b> telle qu'elle est communément utilisée : l'initialisation <b>int i = 0</b> crée un entier <b>i</b> utilisé comme un compteur de boucle et de valeur initiale zéro. La portion de test dit que pour rester dans la boucle, <b>i</b> doit être inférieur au nombre d'éléments du vecteur <b>v</b>. (Cela est déterminé en utilisant la fonction membre <b>size( ), que j'ai glissé ici, mais vous admettrez que sa signification est assez évidente.</b>) La portion finale emploie une notation du C et du C++, l'opérateur d'“auto-incrémentation”, pour ajouter une unité à la valeur de <b>i</b>. En effet, <b>i++</b> signifie “prend la valeur de <b>i</b>, ajoutes-y un, et mets le résultat dans <b>i</b>”. Ainsi, l'ffet global de la boucle <b>for</b> est de prendre une variable <b>i</b> et de l'incrémenter par pas de un à partir de zéro tant qu'elle est inférieure à la taille du vecteur. Pour chaque valeur de <b>i</b>, le <b>cout</b> est exécuté et cela construit une ligne contenant la valeur de <b>i</b> (magiquement convertie en tableau de caractères par <b>cout</b>), deux-points et un espace, la ligne du fichier, et un retour à la ligne amené par <b>endl</b>. Lorsque vous compilerez et exécuterez ce programme, vous verrez que l'effet est d'ajouter une numérotation de ligne au fichier.</paragraph>
<paragraph>Du fait que l'opérateur ‘<b>>></b>’ fonctionne avec iostreams, vous pouvez facilement modifier le programme afin qu'il découpe l'entrée en mots au lieu de lignes :</paragraph>
<code langage="cpp">//: C02:GetWords.cpp
// Break a file into whitespace-separated words
#include <string>
#include <iostream>
#include <fstream>
#include <vector>
using namespace std;
int main() {
vector<string> words;
ifstream in("GetWords.cpp");
string word;
while(in >> word)
words.push_back(word);
for(int i = 0; i < words.size(); i++)
cout << words[i] << endl;
} ///:~</code>
<paragraph>L'expression<paragraph>
<code langage="cpp">while(in >> word)</code>
<paragraph>permet d'obtenir une entrée mot à mot, et quand cette expression est évaluée à faux cela signifie que la fin du fichier a été atteinte. Naturellement, délimiter des mots par un espace est assez brut, mais cela est exemple simple.</paragr Plus tard dans ce livre, vous verrez des exemples plus sophistiqués qui vous permettrons de modificer l'entrée comme vous le souhaitez.</paragraph>
<paragraph>Pour démontrer la facilité d'utilisation d'un vecteur de n'importe quel type, voici un exemple qui crée un <b>vector<int></b> :</paragraph>
<code langage="cpp">//: C02:Intvector.cpp
// Creating a vector that holds integers
#include <iostream>
#include <vector>
using namespace std;
int main() {
vector<int> v;
for(int i = 0; i < 10; i++)
v.push_back(i);
for(int i = 0; i < v.size(); i++)
cout << v[i] << ", ";
cout << endl;
for(int i = 0; i < v.size(); i++)
v[i] = v[i] * 10; // Assignment
for(int i = 0; i < v.size(); i++)
cout << v[i] << ", ";
cout << endl;
} ///:~</code>
<paragraph>Pour créer un <b>vector</b> pour contenir un certain type, vous avez juste à mettre ce type en temps que paramètre de template (entre <b>< ></b>). Les templates et les bibliothèques de templates optimisées sont prévus pour être aussi facile à employer.</paragraph>
<paragraph>Cet exemple va vous montrer un autre aspect essentiel de la classe <b>vector</b>. Dans l'expression</paragraph>
<code langage="cpp">v[i] = v[i] * 10;</code>
<paragraph>vous pouvez voir que le <b>vector</b> n'est pas limité seulement à y mettre des choses et à les récupérer. Vous êtes aussi abilité à <i>assigner</i> (et donc de modifier) n'importe quel élément du vecteur, ceci en utilisant l'opérateur d'indexation crochet. Cela signifie que la classe <b>vector</b> est d'usage universel, flexible pour travailler avec une collection d'objets, et nous en ferons usage dans les chapitres à venir.</paragraph>
</section>
Partager