Evite vazamentos de memória em C++
-
Use o operador
delete
para liberar cadanew
bloco de memória alocado -
Use
std::unique_ptr
para liberar objetos Heap automaticamente
Este artigo demonstrará vários métodos sobre como evitar vazamentos de memória em C++.
Use o operador delete
para liberar cada new
bloco de memória alocado
Vazamentos de memória são um problema comum para os programas que interagem diretamente com a interface de memória dinâmica bruta, o que sobrecarrega o programador para liberar cada memória alocada com o método correspondente. Existem várias interfaces para gerenciamento de memória acessíveis em C++, juntamente com algumas chamadas de sistema específicas da plataforma, que representam essencialmente as funções de nível mais baixo que podem ser utilizadas para essa finalidade. Na maioria dos casos, o programa regular deve usar apenas recursos específicos da linguagem, como operadores new
e delete
para gerenciamento manual de memória ou usar ponteiros inteligentes para desalocação automática de memória.
O método mais vulnerável para vazamentos de memória é usar o new
/delete
operadores para gerenciar diretamente a memória heap. Observe que cada ponteiro retornado da chamada new
deve ser passado para o operador delete
para liberar os blocos de memória correspondentes de volta para o sistema, ou a memória pode se esgotar. Por exemplo, o programa a seguir aloca um array char
de 10 elementos e não a libera antes da saída do programa. Portanto, diz-se que o programa sofre de um vazamento de memória.
#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;
}
Vazamentos de memória podem ser detectados usando o programa valgrind
, que é um utilitário de linha de comando e pode ser executado em um arquivo de programa compilado. Observe que Valgrind
é na verdade um conjunto de várias ferramentas, uma das quais é um utilitário de verificação de memória. O seguinte comando pode ser emitido para investigar vazamentos de memória.
valgrind --tool=memcheck --leak-check=full ./program
Depois de concluída a verificação, a seguinte saída é impressa. Observe que, uma vez que não chamamos delete
no ponteiro arr
, todo o array resultou em memória não alimentada, portanto, o registro - definitivamente perdido: 10 bytes
no resumo de vazamento. O último é o tamanho real do array char 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)
Use std::unique_ptr
para liberar objetos Heap automaticamente
O problema de código do exemplo anterior pode ser corrigido pelo método delete [] arr;
declaração antes de o programa terminar. Embora, outra opção seja utilizar um dos ponteiros inteligentes, por exemplo, std::unique_ptr
. O objeto de ponteiro inteligente pode ser inicializado com o tipo fornecido e armazena o ponteiro retornado do operador new
. A única diferença do ponteiro regular é que a região de memória associada std::unique_ptr
não precisa ser delete
explicitamente. Em vez disso, o compilador cuida da desalocação quando o objeto sai do escopo.
#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