Como pode ocorrer uma fuga de memória ao usar unique_ptr em C++?
sobes.tech IA
Resposta da IA
A fuga de memória ao usar std::unique_ptr pode ocorrer nos seguintes casos:
-
Uso incorreto do destruidor personalizado (Deleter): Se o destruidor personalizado não liberar corretamente o recurso alocado (por exemplo, chamando
deleteem vez dedelete[]para um array ou não chamando a função de liberação adequada).#include <memory> #include <iostream> struct MyDeleter { void operator()(int* ptr) const { // ERRO: deve ser delete[], não delete delete ptr; std::cout << "Chamada ao destruidor incorreto" << std::endl; } }; int main() { // Aloca um array, mas usa um destruidor incorreto std::unique_ptr<int, MyDeleter> ptr(new int[10], MyDeleter()); // A memória alocada como array não será completamente liberada ao sair do escopo de ptr return 0; } -
Passar um ponteiro bruto de
unique_ptrpara uma função que assume posse e não libera: A transferência de posse deve ser feita explicitamente comstd::move. Se você passarget()ou um ponteiro bruto e não cuidar de liberá-lo em outro lugar, isso pode causar vazamento.#include <memory> #include <iostream> void process_and_lose(int* raw_ptr) { // A função "esquece" de fazer delete raw_ptr std::cout << "Processando " << *raw_ptr << std::endl; // Vazamento de memória! } int main() { std::unique_ptr<int> ptr(new int(42)); // Obter um ponteiro bruto int* raw = ptr.get(); process_and_lose(raw); // ptr ainda gerencia a memória, mas raw_ptr se torna órfão // Neste caso, não há vazamento, pois ptr liberará a memória // Mas se ptr fosse resetado ou reatribuído antes da chamada a process_and_lose, // e a função não deletar, haveria vazamento return 0; }Exemplo corrigido com potencial vazamento (se transferirmos a posse, mas a função não deletar):
#include <memory> #include <iostream> void function_that_takes_ownership_and_leaks(int* owned_ptr) { // Presume-se que owned_ptr agora pertence a esta função std::cout << "Tomando posse e vazando: " << *owned_ptr << std::endl; // Vazamento: owned_ptr não é deletado } int main() { std::unique_ptr<int> ptr(new int(100)); // Transferir posse do ponteiro bruto function_that_takes_ownership_and_leaks(ptr.release()); // ptr agora está vazio, seu recurso (ponteiro) não será liberado automaticamente return 0; } -
Exceções entre a alocação de memória e o encapsulamento em
unique_ptr: Emborastd::make_uniqueevite isso, usar diretamentenewseguido do construtorunique_ptrpode causar vazamento se uma exceção ocorrer entre eles.#include <memory> #include <vector> class Resource { public: Resource() { std::cout << "Recurso criado" << std::endl;} ~Resource() { std::cout << "Recurso destruído" << std::endl;} }; void might_throw() { throw std::runtime_error("Opa!"); } int main() { Resource* res = new Resource(); // Alocação de memória try { might_throw(); // Uma exceção ocorre aqui std::unique_ptr<Resource> ptr(res); // Esta linha não será atingida } catch (const std::runtime_error& e) { std::cerr << "Exceção capturada: " << e.what() << std::endl; // res* não foi envolvido em um unique_ptr e não foi deletado // Isso leva a um vazamento! } // Forma correta: std::make_unique<Resource>() ou std::unique_ptr<Resource> ptr(new Resource()); return 0; }
De modo geral, o vazamento de memória ao usar std::unique_ptr corretamente é extremamente improvável, pois seu objetivo principal é gerenciar recursos automaticamente, prevenindo vazamentos em cenários típicos. Problemas surgem quando se sai do uso padrão (destructores personalizados, release(), interação com ponteiros brutos).