Smart Pointers in C++
Smart pointers are wrapper classes around raw pointers that automatically manage memory. They eliminate the need to manually call delete and prevent common memory bugs like memory leaks and dangling pointers. Introduced in C++11, smart pointers are defined in the <memory> header.
The Problem with Raw Pointers
int *p = new int(42);
// ... some code that might throw an exception ...
delete p; // If exception occurs above, this is never reached!
// Result: Memory leak
Smart pointers solve this by automatically releasing memory when they go out of scope — regardless of how the scope is exited.
Types of Smart Pointers
| Smart Pointer | Ownership | Use Case |
|---|---|---|
unique_ptr | Single owner | When only one owner is needed |
shared_ptr | Multiple owners (reference counted) | When multiple parts need the same resource |
weak_ptr | Non-owning observer | To break circular references |
unique_ptr — Exclusive Ownership
A unique_ptr is the sole owner of the memory it manages. When it goes out of scope, the memory is automatically freed. It cannot be copied — only moved.
#include <iostream>
#include <memory>
using namespace std;
int main() {
unique_ptr<int> ptr = make_unique<int>(42);
cout << "Value: " << *ptr << endl;
// No need for delete — memory freed automatically
return 0;
}
Output:
Value: 42unique_ptr with a Class:
class Dog {
public:
string name;
Dog(string n) : name(n) { cout << name << " created.
"; }
~Dog() { cout << name << " destroyed.
"; }
void bark() { cout << name << " says Woof!
"; }
};
int main() {
{
unique_ptr<Dog> d = make_unique<Dog>("Bruno");
d->bark();
} // Bruno is automatically destroyed here
cout << "After block." << endl;
return 0;
}
Output:
Bruno created.
Bruno says Woof!
Bruno destroyed.
After block.Transferring Ownership with move:
unique_ptr<int> p1 = make_unique<int>(10);
unique_ptr<int> p2 = move(p1); // ownership transferred to p2
// p1 is now nullptr
cout << *p2 << endl; // 10
shared_ptr — Shared Ownership
A shared_ptr allows multiple pointers to share ownership of the same object. It maintains a reference count — each time a new shared_ptr points to the object, the count increases. When the count reaches zero, the memory is freed.
#include <iostream>
#include <memory>
using namespace std;
int main() {
shared_ptr<int> p1 = make_shared<int>(100);
shared_ptr<int> p2 = p1; // both share ownership
cout << "Value: " << *p1 << endl;
cout << "Use count: " << p1.use_count() << endl;
p2.reset(); // p2 releases ownership
cout << "After reset, count: " << p1.use_count() << endl;
return 0;
}
Output:
Value: 100
Use count: 2
After reset, count: 1weak_ptr — Non-Owning Reference
A weak_ptr observes an object managed by shared_ptr without affecting the reference count. It is used to break circular references — a situation where two shared_ptrs point to each other, preventing cleanup.
shared_ptr<int> sp = make_shared<int>(42);
weak_ptr<int> wp = sp;
cout << "shared count: " << sp.use_count() << endl; // 1 (wp doesn't count)
if (auto locked = wp.lock()) { // convert to shared_ptr to use
cout << "Value: " << *locked << endl;
}
Output:
shared count: 1
Value: 42Smart Pointer vs Raw Pointer
| Feature | Raw Pointer | Smart Pointer |
|---|---|---|
| Memory management | Manual (delete required) | Automatic |
| Memory leaks | Common if delete is missed | Prevented automatically |
| Null safety | Risky | Safer with checks |
| Overhead | None | Slight overhead (reference counting) |
Best Practices
- Prefer
make_uniqueandmake_sharedovernew— safer and more efficient. - Use
unique_ptrby default — only useshared_ptrwhen shared ownership is truly needed. - Use
weak_ptrto break cycles betweenshared_ptrobjects. - Avoid using raw pointers for ownership — use smart pointers instead.
Key Takeaways
- Smart pointers automatically free memory when they go out of scope.
unique_ptr— single owner; memory released when it goes out of scope.shared_ptr— multiple owners; memory freed when last owner is gone.weak_ptr— non-owning observer; used to avoid circular reference leaks.- Always prefer smart pointers over raw
new/deletefor safer memory management.
