Memória e coletor de lixo em C++: por que seu código não perdoa erros
\n\nQuando um desenvolvedor migra para C++ depois de Python, Java ou C#, muitas vezes leva um banho de água fria. Onde antes era possível simplesmente criar um objeto e esquecê-lo (graças ao coletor de lixo!), no C++ é preciso pensar em cada byte. E isso não é um bug, é uma feature. O C++ não perdoa a preguiça, mas oferece em troca controle absoluto sobre a memória — e, consequentemente, sobre o desempenho.
\n\nNeste artigo, vamos analisar por que o C++ não possui um coletor de lixo (GC) embutido, como funciona o gerenciamento manual de memória e quais ferramentas modernas (RAII, ponteiros inteligentes) permitem escrever código seguro e rápido sem dor de cabeça. Se você programa em C++ ou está começando — este material é para você.
\n\nMito nº 1: C++ tem um coletor de lixo
\n\nVamos dissipar o principal equívoco imediatamente. No C++ padrão (ISO C++98/11/14/17/20/23) não há um coletor de lixo embutido. Sim, você pode conectar uma biblioteca externa (por exemplo, libgc de Hans Boehm), mas isso será uma gambiarra, não um mecanismo nativo. Por quê?
- \n
- Filosofia do C++: "Você não paga pelo que não usa". O coletor de lixo consome recursos (CPU, memória) e introduz pausas não determinísticas. Para sistemas de tempo real, jogos, embedded — isso é fatal. \n
- Determinismo: No C++, você sabe exatamente quando um objeto será destruído. No GC — não (apenas "algum dia"). \n
- RAII (Resource Acquisition Is Initialization) — este é o nosso "coletor de lixo", mas manual e previsível. \n
Como funciona o gerenciamento manual de memória em C++
\n\nO clássico: new e delete. Alocou memória no heap — não esqueça de liberar.
#include <iostream>\n\nint main() {\n int* p = new int(42); // alocamos memória para um int\n std::cout << *p << std::endl;\n delete p; // liberamos — senão, vazamento\n return 0;\n}\n\nParece simples? Agora imagine que entre new e delete pode ocorrer uma exceção, um return, ou alguém esquecer de chamar delete. Temos o clássico vazamento de memória em C++. E isso é só o começo: deleção dupla (double delete), ponteiros pendentes (dangling pointers) — aí é que está o verdadeiro inferno.
RAII — o melhor amigo do desenvolvedor C++
\n\nRAII não é apenas uma sigla, é um estilo de vida em C++. A ideia: o recurso (memória, arquivo, mutex) é adquirido no construtor e liberado no destrutor. Assim que o objeto sai do escopo — o destrutor é chamado automaticamente. Garantidamente.
\n\nExemplo com o ponteiro inteligente std::unique_ptr:
#include <memory>\n#include <iostream>\n\nclass MyClass {\npublic:\n MyClass() { std::cout << "Criado\\n"; }\n ~MyClass() { std::cout << "Destruído\\n"; }\n};\n\nint main() {\n std::unique_ptr<MyClass> ptr = std::make_unique<MyClass>();\n // Nada de delete! A memória será liberada automaticamente ao sair do bloco\n return 0;\n}\n\nSaída: Criado, depois Destruído. Sem vazamentos, sem chamada manual. RAII substitui o coletor de lixo em C++ — mas faz isso de forma previsível e sem pausas.
Ponteiros inteligentes: unique_ptr, shared_ptr, weak_ptr
\n\nSe você ainda está usando new/delete puros — pare. O C++ moderno (a partir do C++11) oferece ponteiros inteligentes que automatizam o gerenciamento de memória.
std::unique_ptr
\nPropriedade exclusiva. Não pode ser copiado, apenas movido. Ideal para posse exclusiva de um recurso.
\n\nstd::unique_ptr<int> p1 = std::make_unique<int>(10);\n// std::unique_ptr<int> p2 = p1; // Erro! Cópia proibida\nstd::unique_ptr<int> p2 = std::move(p1); // Ok, transferência de posse\n\n