mercredi 21 avril 2010

C++ & STL : les pièges du conteneur 'vector'

Le conteneur 'vector' est très pratique d'utilisation mais souffre à mon avis d'un défaut majeur: il est trop tolérant avec l'utilisateur, ce qui se retourne après (souvent...) contre celui-ci.

Par exemple, l'opérateur [] est défini, ce qui rend l'usage de ce conteneur intuitif pour les programmeurs venant du C, en remplacement des tableaux. On pourra ainsi écrire:
vector<int> tab(10);
tab[0] = 3;

de la même façon qu'on écrivait en C:
int tab[10];
tab[0] = 3;

Mais ceci se révèle après coup TRES DANGEREUX. En effet il n'y a pas de vérification de la validité de l'indice dans cette notation. En vérifiant dans l'implémentation de Mingw, on y trouve le commentaire suivant:
This operator allows for easy, array-style, data access. Note that data access with this operator is unchecked and out_of_range lookups are not defined.

Ceci est d'ailleurs rappelé sur la page Wikipedia du conteneur 'vector'.

Et que ce passe-t-il en pratique ? Et bien, loi de Murphy oblige, ça arrive un jour ou l'autre (croyez moi...). Et donc, crash. Bon, un crash, soit, mais... et alors me direz vous ?
Et bien, ce type de crash est lié à une corruption mémoire, et le problème, c'est qu'il est extrêmement difficile à pister. Contre toute attente, le crash ne se produit pas lors de l'exécution de l'accès au vector, mais à un autre endroit du programme, là où rien de spécial n'est exécuté...

En conclusion, si vous avez moins de 5 ans d'expérience en C++, et que vous travaillez sur un projet conséquent en C++, ne jamais utiliser la notation '[]' mais TOUJOURS la méthode 'at()', qui effectue la vérification de validité d'indice.

* Liens:
Edit 20121102: En fait, sous GCC, on peut activer le bound checking pour les conteneurs de la STL. Il suffit de compiler en définissant le symbole _GLIBCXX_DEBUG (soit l'ajout du flag -D_GLIBCXX_DEBUG). Ceci est décrit ici. Source: stackoverflow.com/questions/1290396.