Evite pérdidas de memoria en C++
-
Utilice el operador
delete
para liberar cada bloque de memoria asignadonew
-
Utilice
std::unique_ptr
para liberar automáticamente los objetos del montón
Este artículo mostrará varios métodos sobre cómo evitar pérdidas de memoria en C++.
Utilice el operador delete
para liberar cada bloque de memoria asignado new
Las pérdidas de memoria son un problema común para los programas que interactúan directamente con la interfaz de memoria dinámica sin procesar, lo que impone al programador una carga para liberar cada memoria asignada con el método correspondiente. Existen múltiples interfaces para la administración de memoria accesibles en C++ junto con algunas llamadas al sistema específicas de la plataforma, que esencialmente representan las funciones de nivel más bajo que se pueden utilizar para este propósito. En la mayoría de los casos, el programa normal solo debería utilizar facilidades específicas del idioma como operadores new
y delete
para la gestión manual de la memoria o utilizar punteros inteligentes para la desasignación automática de memoria.
El método más vulnerable para las fugas de memoria es utilizar el new
/delete
operadores para administrar directamente la memoria del montón. Tenga en cuenta que cada puntero devuelto por la llamada new
debe pasarse al operador delete
para liberar los bloques de memoria correspondientes al sistema, o la memoria podría agotarse. Por ejemplo, el siguiente programa asigna un array char
de 10 elementos y no la libera antes de salir del programa. Por lo tanto, se dice que el programa sufre una pérdida de memoria.
#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;
}
Las pérdidas de memoria se pueden detectar utilizando el programa valgrind
, que es una utilidad de línea de comandos y se puede ejecutar en un archivo de programa compilado. Tenga en cuenta que Valgrind
es en realidad un conjunto de múltiples herramientas, una de las cuales es una utilidad de verificación de memoria. Se puede emitir el siguiente comando para investigar pérdidas de memoria.
valgrind --tool=memcheck --leak-check=full ./program
Una vez realizada la comprobación, se imprime la siguiente salida. Tenga en cuenta que, dado que no llamamos a delete
en el puntero arr
, toda el array resultó en memoria no liberada, de ahí el registro: definitivamente perdido: 10 bytes
en el resumen de fugas. Este último es el tamaño real del array de caracteres de 10 elementos.
==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)
Utilice std::unique_ptr
para liberar automáticamente los objetos del montón
El problema del código de ejemplo anterior se puede solucionar con delete [] arr;
declaración antes de que salga el programa. Aunque, otra opción es utilizar uno de los punteros inteligentes, p. Ej. std::unique_ptr
. El objeto de puntero inteligente se puede inicializar con el tipo dado y almacena el puntero devuelto por el operador new
. La única diferencia con el puntero normal es que la región de memoria asociada std::unique_ptr
no necesita ser delete
explícitamente. En cambio, el compilador se encarga de la desasignación una vez que el objeto sale del alcance.
#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