La STL fournit une classe très pratique pour faire tout un tas de choses intéressantes avec les chaînes de caractères : std::string. Malheureusement, les fameuses fonctions trim, rtrim et ltrim que l'on peut trouver en PHP n'ont pas été implémentées.
Supprimer les espaces en début et en fin de chaîne
Évitez les chiffres magiques
Vous êtes de ceux qui utilisent des chiffres directement dans le code ? Lisez ceci, vous allez très vite changer d'avis.
Effectuez des copies entières de vos objets
Nous avons vu précédemment que le compilateur pouvait créer automatiquement le constructeur par copie et l'opérateur d'affectation. Ces éléments par défaut suffisent la plupart du temps, à moins que les objets à copier contiennent des pointeurs, des constantes ou des références. Si vous avez écrit le constructeur par copie et l'opérateur d'affectation, sachez qu'il y a quelques pièges à éviter.
Bien utiliser l'opérateur =
Aujourd'hui, nous allons voir comment bien implémenter l'opérateur d'affectation du C++ : operator=.
Cet opérateur est souvent victime d'au moins une des deux erreurs suivantes : soit la signature de cet opérateur n'est pas correcte, ce qui rend impossible l'utilisation des affectations chainées, soit l'auto-affectation n'est pas prise en compte et l'objet qui est auto-copié est alors corrompu. Suivez le guide...
Déclarez virtuels les destructeurs de vos classes polymorphes
Si vous créez des classes polymorphes, c'est-à-dire, héritant d'autres classes, vous devez déclarer vos destructeurs virtuels si vous ne souhaitez pas avoir des comportements étranges ainsi que des fuites mémoire.
Interdire la copie d'objets
C++ génère automatiquement pour vous le constructeur par copie et l'opérateur d'affectation si vous ne les avez pas définis et qu'une partie de votre code y fait appel. Dans certains cas, vous désirerez peut-être que ces éléments ne soient pas générés afin d'interdire la copie d'objets. Cela peut être utile si par exemple une copie est trop complexe ou trop longue à mettre en place, ou encore si cette copie ne veut rien dire sémantiquement...
Constructeurs par défaut, par copie, destructeur et opérateur d'affectation
La plupart des classes C++ que l'on crée possèdent généralement au moins un constructeur, un destructeur et un opérateur d'affectation. Si vous ne les avez pas déclarés, le compilateur le fera pour vous.
Préférez const et inline aux #define
Les macros du C c'est mal, vous ne devriez pas les utiliser en C++. En effet, C++ fournit tout un tas de mécanismes permettant de combler les lacunes du C. Il faut privilégier le compilateur au préprocesseur. Il ne faut donc pas utiliser #define pour créer des constantes ou des fonctions.
Préférez les commentaires C++ à ceux du C
Les commentaires multi-lignes du C /* ... */ fonctionnent également en C++ mais vous devriez éviter de les utiliser. Le commentaire de fin de ligne C++ // ... a des avantages indéniables.
Utiliser les vecteurs de la STL
Les tableaux dynamiques, c'est bien mais ce n'est pas très pratique. Une fois leur taille fixée, on ne peut plus la changer. Comme il est rare que l'on connaisse cette taille à l'avance, on a tendance à la surdimensionner pour être tranquille, ce qui engendre une surconsommation de mémoire. La STL fournit la solution à ce problème. En effet, elle propose de nombreux conteneurs très utiles. Celui auquel nous allons nous intéresser aujourd'hui, le plus simple d'entre-eux est std::vector. Il ressemble fort à un tableau mais présente de nombreux avantages notamment en termes d'accès et il est capable de s'agrandir lorsque sa mémoire est pleine. Il est également plus sécurisé. Le vecteur est le conteneur que vous devez utiliser par défaut.
Améliorez votre code avec const
Le mot-clé const est malheureusement très peu utilisé par les programmeurs, soit par oubli, soit parce qu'ils jugent ce mot-clé inutile ou encore parce qu'ils ne connaissent pas les bienfaits qu'il procure. Pourtant, il devrait être considéré comme un réel atout du C++ parce qu'il rend le style de programmation meilleur : plus rapide, plus robuste, plus sécurisé, etc.
Derniers Commentaires
Bonjour,
Merci pour ces précisions. Ces techniques pourront en effet faire l'objet d'un nouvel article. C'est d'ailleurs un peu pour ça que je n'en ai pas parlées, car on peut vite dévier sur un autre sujet.
Bonjour,
une petite remarque sur un problème non adressé par cet article : la résistance aux exceptions. Un opérateur= se doit d'être résistant aux exceptions. En termes simples, si une exception est levée pendant l'exécution de l'operator=(), alors il faut faire en sorte que l'instance en cours de modification ne soit pas modifiée - sans quoi on la retrouve dans un état inconnu, avec un invariant invalide (et tout les problèmes que cela pose si, plus tard, cet objet est réutilisé).
Une approche est d'utiliser les idiomes RAII et swap. Le code de copie se trouve alors principalement dans une méthode swap(), qui peut être utilisée dans l'operator=() de cette manière :
C& C::operator=(const C& other) { C(other).swap(*this); return *this; }cf Copy-and-swap Idiom, Non-throwing swap et RAII
Effectivement, les deux premiers exemples n'utilisaient pas la liste d'initialisation pour le constructeur par copie, c'est maintenant chose faite. Merci.
Je souhaite juste apporter une précision sur les variables statique de classe.
Tel que tu le présentes, il a un gros désavantage. L'ensemble des unités de code qui incluront l'en-tête de définition de la classe auront leur propre variable statique. Pour des const, ce n'est pas très gênant (encore que, si on modifie l'en-tête et que toutes les unités qui en dépendent ne sont pas recompilées, ça peut poser problème).
Un article concernant externe, lié à cet article, serait le bienvenu
Un constructeur de copie est un constructeur comme les autres : la liste d'initialisation y est tout indiquée.