Évitez les fuites de mémoire en C++
-
Utilisez l’opérateur
delete
pour libérer chaquenew
bloc mémoire alloué -
Utilisez
std::unique_ptr
pour libérer automatiquement les objets du tas
Cet article présente plusieurs méthodes sur la façon d’éviter les fuites de mémoire dans C++.
Utilisez l’opérateur delete
pour libérer chaque new
bloc mémoire alloué
Les fuites de mémoire sont un problème courant pour les programmes qui interagissent directement avec l’interface de mémoire dynamique brute, ce qui oblige le programmeur à libérer chaque mémoire allouée avec la méthode correspondante. Il existe plusieurs interfaces pour la gestion de la mémoire accessibles en C++ ainsi que certains appels système spécifiques à la plate-forme, qui représentent essentiellement les fonctions de niveau le plus bas pouvant être utilisées à cette fin. Dans la plupart des cas, le programme régulier ne devrait utiliser que des fonctionnalités spécifiques à la langue comme les opérateurs new
et delete
pour la gestion manuelle de la mémoire ou utiliser des pointeurs intelligents pour la désallocation automatique de la mémoire.
La méthode la plus vulnérable aux fuites de mémoire consiste à utiliser les opérateurs new
/delete
pour gérer directement la mémoire du tas. Notez que chaque pointeur renvoyé par le new
appel doit être passé à l’opérateur delete
pour libérer les blocs de mémoire correspondants dans le système, sinon la mémoire pourrait s’épuiser. Par exemple, le programme suivant alloue un tableau char
à 10 éléments et ne le libère pas avant la fin du programme. Ainsi, le programme souffrirait d’une fuite de mémoire.
#include <iostream>
using std::cout;
using std::endl;
constexpr int SIZE = 10;
int main() {
char *arr = new char[SIZE];
for (int i = 0; i < SIZE; ++i) {
arr[i] = (char)(65 + i);
cout << arr[i] << "; ";
}
cout << endl;
return EXIT_SUCCESS;
}
Les fuites de mémoire peuvent être détectées à l’aide du programme valgrind
, qui est un utilitaire en ligne de commande et peut être exécuté sur un fichier programme compilé. Notez que Valgrind
est en fait un ensemble d’outils multiples, dont l’un se trouve être un utilitaire de vérification de la mémoire. La commande suivante peut être émise pour rechercher des fuites de mémoire.
valgrind --tool=memcheck --leak-check=full ./program
Une fois la vérification terminée, la sortie suivante est imprimée. Notez que, puisque nous n’avons pas appelé delete
sur le pointeur arr
, l’ensemble du tableau a entraîné une mémoire non libérée d’où l’enregistrement - definitely lost: 10 bytes
dans le résumé de la fuite. Ce dernier est la taille réelle du tableau de caractères à 10 éléments.
==13732== HEAP SUMMARY:
==13732== in use at exit: 10 bytes in 1 blocks
==13732== total heap usage: 3 allocs, 2 frees, 73,738 bytes allocated
==13732==
==13732== 10 bytes in 1 blocks are definitely lost in loss record 1 of 1
==13732== at 0x483C583: operator new[](unsigned long) (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==13732== by 0x1091FE: main (tmp.cpp:11)
==13732==
==13732== LEAK SUMMARY:
==13732== definitely lost: 10 bytes in 1 blocks
==13732== indirectly lost: 0 bytes in 0 blocks
==13732== possibly lost: 0 bytes in 0 blocks
==13732== still reachable: 0 bytes in 0 blocks
==13732== suppressed: 0 bytes in 0 blocks
==13732==
==13732== For lists of detected and suppressed errors, rerun with: -s
==13732== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
Utilisez std::unique_ptr
pour libérer automatiquement les objets du tas
Le problème de code d’exemple précédent peut être résolu par le bouton delete [] arr;
instruction avant que le programme ne se termine. Bien qu’une autre option consiste à utiliser l’un des pointeurs intelligents, par ex. std::unique_ptr
. L’objet pointeur intelligent peut être initialisé avec le type donné et stocke le pointeur renvoyé par l’opérateur new
. La seule différence avec le pointeur normal est que la région mémoire associée std::unique_ptr
n’a pas besoin d’être delete
explicitement. Au lieu de cela, le compilateur s’occupe de la désallocation une fois que l’objet sort de la portée.
#include <iostream>
#include <memory>
using std::cout;
using std::endl;
constexpr int SIZE = 10;
int main() {
std::unique_ptr<char[]> arr(new char[SIZE]);
for (int i = 0; i < SIZE; ++i) {
arr[i] = (char)(65 + i);
cout << arr[i] << "; ";
}
cout << endl;
return EXIT_SUCCESS;
}
Founder of DelftStack.com. Jinku has worked in the robotics and automotive industries for over 8 years. He sharpened his coding skills when he needed to do the automatic testing, data collection from remote servers and report creation from the endurance test. He is from an electrical/electronics engineering background but has expanded his interest to embedded electronics, embedded programming and front-/back-end programming.
LinkedIn Facebook