Revue de code en C++ : que vérifier et comment donner un retour
\n\nLa revue de code est l'une des étapes clés du développement logiciel. C'est particulièrement important pour le C++, où les erreurs de gestion de la mémoire ou l'utilisation incorrecte de la bibliothèque standard peuvent entraîner de sérieux problèmes. Dans cet article, nous allons examiner sur quoi se concentrer lors de la revue de code en C++ et comment donner un feedback pour qu'il soit utile, et non blessant.
\n\nPourquoi la revue de code est-elle importante pour le C++ ?
\n\nLe C++ est un langage puissant mais complexe. Il offre au développeur un haut niveau de contrôle, mais exige également de l'attention. Les problèmes typiques : fuites mémoire, comportement indéfini, algorithmes inefficaces. Une bonne revue de code permet de détecter ces erreurs avant qu'elles n'atteignent la production.
\n\nPour les développeurs débutants, la revue de code n'est pas seulement une vérification, mais aussi un apprentissage. En recevant un feedback, vous apprenez à écrire un code de meilleure qualité. En faisant une revue, vous apprenez à analyser et à argumenter.
\n\nQue vérifier dans le code C++ : checklist
\n\nPour que la revue soit systématique, utilisez la checklist suivante.
\n\n1. Gestion de la mémoire et des ressources
\n\nC'est la base du C++. Les erreurs ici sont les plus dangereuses.
\n- \n
- Les pointeurs intelligents sont-ils utilisés à la place des pointeurs bruts ?
std::unique_ptretstd::shared_ptrdevraient être la norme. Les pointeurs bruts ne sont acceptables que pour l'observation (non propriétaire). \n - Y a-t-il des fuites ? Vérifiez que chaque
newa undeletecorrespondant (si les pointeurs intelligents ne sont pas utilisés). \n - Les ressources sont-elles correctement libérées ? Les fichiers, sockets, mutex doivent être encapsulés dans des classes RAII. \n
// Mauvais : pointeur brut et gestion manuelle\nvoid process() {\n int* data = new int[100];\n // ... si une exception survient ici, il y a une fuite\n delete[] data;\n}\n\n// Bon : pointeur intelligent\nvoid process() {\n auto data = std::make_unique<int[]>(100);\n // la mémoire sera libérée automatiquement\n}\n\n2. Sécurité des types et évitement du comportement indéfini
\n\nLe C++ est plein de comportements indéfinis (UB). Le relecteur doit être vigilant.
\n- \n
- Y a-t-il un dépassement de tableau ? Utilisez
std::arrayoustd::vectoravec.at()au lieu de tableaux bruts. \n - Le transtypage est-il correct ? Évitez les casts de style C. Utilisez
static_cast,dynamic_cast,const_castoureinterpret_castde manière réfléchie. \n - Toutes les variables sont-elles initialisées ? Les variables non initialisées sont une cause fréquente d'UB. \n
- Y a-t-il un débordement d'entiers signés ? En C++, c'est un UB. \n
// Mauvais : cast de style C et variable non initialisée\nint* p = (int*)malloc(sizeof(int));\nint x; // non initialisé\n*p = x; // UB\n\n// Bon : transtypage explicite et initialisation\nint* p = static_cast<int*>(std::malloc(sizeof(int)));\nint x = 0;\n*p = x;\n\n3. Performance et efficacité
\n\nIl n'est pas toujours nécessaire de rechercher la vitesse, mais les goulots d'étranglement évidents méritent d'être corrigés.
\n- \n
- Les objets sont-ils passés par valeur inutilement ? Les objets volumineux doivent être passés par référence constante (
const &). \n - Y a-t-il des copies inutiles ? Utilisez la sémantique de déplacement lorsque c'est approprié. \n
- Le conteneur est-il correctement choisi ?
std::vectorpour un accès rapide par index,std::listpour des insertions fréquentes au milieu. \n - Une fonction virtuelle est-elle appelée dans une boucle chaude ? Cela peut être lent. \n
// Lent : copie d'un objet volumineux\nvoid process(std::string s) { /* ... */ }\n\n// Rapide : passage par référence constante\nvoid process(c