In C++, memory management is performed using explicit operators new and delete that allocate and free memory dynamically. However, manual management easily leads to memory leaks or double deletion.
With the introduction of C++11, smart pointers were introduced — such as std::unique_ptr, std::shared_ptr, std::weak_ptr. They automatically manage the lifecycle of objects and ensure resource deallocation when they go out of scope, even in the event of an exception.
Example comparison:
// Manual memory deallocation Foo* ptr = new Foo(); // ... delete ptr; // Safer with a smart pointer std::unique_ptr<Foo> ptr2 = std::make_unique<Foo>(); // delete is not required — unique_ptr will handle it for you
Smart pointers reduce the risk of memory leaks and make the code safer and more readable.
What happens if you call delete twice on the same pointer?
Answer: After the first delete call, the memory has already been freed. A second call will lead to undefined behavior. Example:
Foo* p = new Foo(); delete p; delete p; // ERROR!
To avoid this, set the pointer to nullptr after deallocation:
delete p; p = nullptr;
Story
In a large C++ project, a developer manually deallocated dynamic memory with
delete, forgetting to remove the pointer when exiting several branches of the function with exceptions. This led to memory leaks that were only identified during load testing.
Story
When attempting to share raw pointers between different parts of the code, double memory deallocation occurred — one part of the code called
deletewithout notifying the others. Result: segfault in production, analysis of the core dump immediately revealed the cause.
Story
After migrating an old project to new C++ standards, part of the code with raw pointers was left, while new classes worked with smart pointers. They encountered errors with resource ownership transfer: memory was deallocated "twice" — first manually, then automatically by the destructors of smart pointers.