How can a memory leak occur when using unique_ptr in C++?
sobes.tech AI
Answer from AI
Memory leaks when using std::unique_ptr can occur in the following cases:
-
Incorrect use of a custom deleter: If the custom deleter does not properly release the allocated resource (for example, calling
deleteinstead ofdelete[]for an array or not calling the appropriate resource release function).#include <memory> #include <iostream> struct MyDeleter { void operator()(int* ptr) const { // ERROR: should be delete[], not delete delete ptr; std::cout << "Called incorrect deleter" << std::endl; } }; int main() { // Allocate an array but use an incorrect deleter std::unique_ptr<int, MyDeleter> ptr(new int[10], MyDeleter()); // Memory allocated as an array will not be fully freed upon scope exit of ptr return 0; } -
Passing a raw pointer from
unique_ptrto a function that then takes ownership and does not free it: Ownership transfer should be explicit usingstd::move. If you passget()or a raw pointer and then do not handle freeing it elsewhere, it can lead to leaks.#include <memory> #include <iostream> void process_and_lose(int* raw_ptr) { // Function "forgets" to delete raw_ptr std::cout << "Processing " << *raw_ptr << std::endl; // Memory leak! } int main() { std::unique_ptr<int> ptr(new int(42)); // Get raw pointer int* raw = ptr.get(); process_and_lose(raw); // ptr still manages the memory, but raw_ptr is now a orphan // In this case, no leak occurs because ptr will free the memory // But if ptr was reset or reassigned before the call to process_and_lose, // and process_and_lose did not delete it, a leak would occur return 0; }Corrected example with potential leak (if ownership is transferred but the function does not delete):
#include <memory> #include <iostream> void function_that_takes_ownership_and_leaks(int* owned_ptr) { // Assumes owned_ptr now belongs to this function std::cout << "Taking ownership and leaking: " << *owned_ptr << std::endl; // Leak: owned_ptr is not deleted } int main() { std::unique_ptr<int> ptr(new int(100)); // Transfer ownership of raw pointer function_that_takes_ownership_and_leaks(ptr.release()); // ptr is now empty, its resource (pointer) will not be automatically freed return 0; } -
Exceptions between memory allocation and wrapping in
unique_ptr: Althoughstd::make_uniqueprevents this, directly usingnewfollowed by constructing aunique_ptrcan lead to leaks if an exception occurs between them.#include <memory> #include <vector> class Resource { public: Resource() { std::cout << "Resource created" << std::endl;} ~Resource() { std::cout << "Resource destroyed" << std::endl;} }; void might_throw() { throw std::runtime_error("Oops!"); } int main() { Resource* res = new Resource(); // Memory allocation try { might_throw(); // Exception occurs here std::unique_ptr<Resource> ptr(res); // This line will not be reached } catch (const std::runtime_error& e) { std::cerr << "Caught exception: " << e.what() << std::endl; // res* was not wrapped in unique_ptr and not deleted // This leads to a leak! } // Correct way: std::make_unique<Resource>() or std::unique_ptr<Resource> ptr(new Resource()); return 0; }
Overall, memory leaks when using std::unique_ptr correctly are very unlikely, as its main purpose is automatic resource management, preventing leaks in typical scenarios. Issues arise when stepping outside its standard usage (custom deleters, release(), interaction with raw pointers).