Advanced10 min readLesson 41 of 50
Why Smart Pointers?
Raw pointers require manual new/delete, risking memory leaks. Smart pointers (C++11, <memory>) manage memory automatically using RAII.
unique_ptr — Exclusive Ownership
#include <iostream>
#include <memory>
using namespace std;
struct Resource {
string name;
Resource(string n) : name(n) { cout << name << " created\n"; }
~Resource() { cout << name << " destroyed\n"; }
};
int main() {
{
unique_ptr<Resource> p1 = make_unique<Resource>("DB Connection");
cout << "Using: " << p1->name << endl;
} // p1 goes out of scope — automatically destroyed
cout << "After scope" << endl;
return 0;
}
Output:
DB Connection created
Using: DB Connection
DB Connection destroyed
After scope
shared_ptr — Shared Ownership
Multiple shared_ptrs can own the same resource. It is destroyed when the last owner goes out of scope (reference counting).
shared_ptr<Resource> p1 = make_shared<Resource>("Config");
{
shared_ptr<Resource> p2 = p1; // shared ownership
cout << "Use count: " << p1.use_count() << endl; // 2
} // p2 destroyed, use_count drops to 1
cout << "Use count: " << p1.use_count() << endl; // 1
// When p1 goes out of scope, Resource is finally destroyed
weak_ptr — Non-Owning Observer
weak_ptr observes a shared_ptr without extending its lifetime — breaks circular references:
shared_ptr<int> sp = make_shared<int>(42);
weak_ptr<int> wp = sp;
if (auto locked = wp.lock()) { // check if still alive
cout << *locked << endl; // 42
}
Rule: Prefer unique_ptr by default. Use shared_ptr when ownership is genuinely shared. Use weak_ptr to break circular shared_ptr cycles.
Exercise
Create a FileLogger class. Use unique_ptr to manage it in main. Transfer ownership to a function process(unique_ptr<FileLogger>) using std::move.
Show Solution
#include <iostream>
#include <memory>
using namespace std;
class FileLogger {
public:
FileLogger() { cout << "Logger opened\n"; }
~FileLogger() { cout << "Logger closed\n"; }
void log(const string& msg) { cout << "[LOG] " << msg << endl; }
};
void process(unique_ptr<FileLogger> logger) {
logger->log("Processing...");
} // logger destroyed here
int main() {
auto logger = make_unique<FileLogger>();
logger->log("Starting");
process(move(logger)); // transfer ownership
// logger is now null
return 0;
}
Quiz
Which smart pointer allows only one owner?
- A) shared_ptr
- B) weak_ptr
- C) unique_ptr
- D) auto_ptr
Answer
C) unique_ptr
What does weak_ptr prevent?
- A) Memory allocation
- B) Circular references that prevent destruction
- C) Multiple ownership
- D) Stack overflow
Answer
B) weak_ptr breaks circular shared_ptr cycles that would cause memory leaks.
Summary
unique_ptr — single owner, zero overhead, use move() to transfer.shared_ptr — reference-counted shared ownership.weak_ptr — non-owning observer, breaks cycles.- Always use
make_unique and make_shared — never use raw new.