Smart Pointers in C++
Part of the Object Oriented Programming section of Coddy's C++ journey — lesson 15 of 104.
Smart pointers are wrapper classes that automatically manage heap memory for you. They eliminate the need for manual delete calls by cleaning up memory when the pointer goes out of scope.
Include the <memory> header to use smart pointers.
unique_ptr - exclusive ownership. Only one pointer can own the resource at a time.
#include <memory>
std::unique_ptr<Player> player = std::make_unique<Player>("Hero");
player->attack(); // Use like a regular pointer
// Cannot copy, but can transfer ownership
std::unique_ptr<Player> player2 = std::move(player);
// player is now nullptrshared_ptr - shared ownership. Multiple pointers can own the same resource. Memory is freed when the last owner is destroyed.
std::shared_ptr<Player> p1 = std::make_shared<Player>("Hero");
std::shared_ptr<Player> p2 = p1; // Both own the resource
std::cout << p1.use_count(); // Prints 2weak_ptr - non-owning observer of a shared_ptr. Useful to break circular references.
std::shared_ptr<Player> shared = std::make_shared<Player>("Hero");
std::weak_ptr<Player> weak = shared;
if (auto locked = weak.lock()) { // Convert to shared_ptr
locked->attack();
}Use unique_ptr by default for single ownership. Use shared_ptr when multiple objects need to share a resource. Use weak_ptr to observe without extending lifetime.
Prefer make_unique and make_shared over raw new.
Challenge
EasyLet's build a document sharing system that demonstrates the different ownership models of smart pointers. You'll see how unique_ptr enforces exclusive ownership, how shared_ptr allows multiple owners, and how weak_ptr can observe without affecting lifetime.
You'll create two files to organize your code:
Document.h: Define aDocumentclass that represents a shareable document. It should have:- A private
titleattribute (string) - A constructor that takes a title and prints
"Document created: <title>" - A destructor that prints
"Document deleted: <title>" - A
getTitle()method that returns the title
- A private
main.cpp: Demonstrate all three smart pointer types by reading a document title from input, then:- Create a
unique_ptrto a Document with the input title - Print
"Unique owner: <title>" - Transfer ownership to another
unique_ptrusingstd::move - Print
"Ownership transferred" - Create a
shared_ptrto a new Document with title"SharedDoc" - Create a second
shared_ptrpointing to the same document - Print
"Shared owners: <count>"usinguse_count() - Create a
weak_ptrfrom one of the shared pointers - Use
lock()to access the document through the weak pointer and print"Weak access: <title>"
- Create a
Remember to include <memory> for smart pointers. Use std::make_unique and std::make_shared to create your smart pointers. The destructor messages will help you see when each document is automatically cleaned up at the end of the program.
Include your header file in main.cpp using #include "Document.h".
Cheat sheet
Smart pointers are wrapper classes that automatically manage heap memory. Include the <memory> header to use them.
unique_ptr
Exclusive ownership - only one pointer can own the resource at a time:
std::unique_ptr<Player> player = std::make_unique<Player>("Hero");
player->attack(); // Use like a regular pointer
// Transfer ownership with std::move
std::unique_ptr<Player> player2 = std::move(player);
// player is now nullptrshared_ptr
Shared ownership - multiple pointers can own the same resource. Memory is freed when the last owner is destroyed:
std::shared_ptr<Player> p1 = std::make_shared<Player>("Hero");
std::shared_ptr<Player> p2 = p1; // Both own the resource
std::cout << p1.use_count(); // Prints 2weak_ptr
Non-owning observer of a shared_ptr. Useful to break circular references:
std::shared_ptr<Player> shared = std::make_shared<Player>("Hero");
std::weak_ptr<Player> weak = shared;
if (auto locked = weak.lock()) { // Convert to shared_ptr
locked->attack();
}Best practices: Use unique_ptr by default for single ownership. Use shared_ptr when multiple objects need to share a resource. Use weak_ptr to observe without extending lifetime. Prefer make_unique and make_shared over raw new.
Try it yourself
#include <iostream>
#include <memory>
#include <string>
#include "Document.h"
using namespace std;
int main() {
string inputTitle;
cin >> inputTitle;
// TODO: Create a unique_ptr to a Document with inputTitle
// using std::make_unique
// TODO: Print "Unique owner: <title>"
// TODO: Transfer ownership to another unique_ptr using std::move
// TODO: Print "Ownership transferred"
// TODO: Create a shared_ptr to a new Document with title "SharedDoc"
// using std::make_shared
// TODO: Create a second shared_ptr pointing to the same document
// TODO: Print "Shared owners: <count>" using use_count()
// TODO: Create a weak_ptr from one of the shared pointers
// TODO: Use lock() to access the document through weak_ptr
// and print "Weak access: <title>"
return 0;
}
This lesson includes a short quiz. Start the lesson to answer it and track your progress.
All lessons in Object Oriented Programming
1Fundamentals of OOP
External FilesC++ Build & CompilationHeader Files & Source FilesNamespaces & ScopeIntroduction to OOP in C++Classes vs ObjectsThe 'this' PointerMethods (Member Functions)Attributes (Data Members)Ctors & Dtors BasicsRecap - Simple Calculator4Class Properties
Instance vs Static MembersGetters and SettersConst Member FunctionsMutable KeywordStatic Methods and VariablesFriend Functions & ClassesRecap - Bank Account Manager7Inheritance
Basic InheritanceInheritance Access LevelsCtor & Dtor Call OrderMethod OverridingVirtual Functions & VTableMultiple InheritanceVirtual InheritanceRecap - Employee Hierarchy2Memory Management
Stack vs Heap MemoryPointers and ReferencesDynamic Memory (new/delete)Smart Pointers in C++RAII in C++Recap - Dynamic Array Manager5Encapsulation
Access Specifiers in C++Access Specifiers In DepthInformation HidingStruct vs ClassNested & Inner ClassesRecap - Student Records System8Polymorphism
Compile vs Runtime PolymorphFunction OverloadingVirtual Functions RevisitedPure Virtual FunctionsAbstract ClassesInterface Design in C++Dynamic Casting & RTTIRecap - Shape Calculator3Constructors & Destructors
Default ConstructorParameterized ConstructorCopy ConstructorMove ConstructorConstructor Init ListsDelegating ConstructorsDestructor Deep DiveRule of Three / Five / ZeroRecap - String Class6Operator Overloading
Intro to Operator OverloadArithmetic Operator OverloadComparison Operator OverloadStream OperatorsAssignment Operator Overload[] and () Operator OverloadType Conversion OperatorsRecap - Matrix Class9Templates
Function TemplatesClass TemplatesTemplate SpecializationVariadic TemplatesSFINAE & Type Traits BasicsRecap - Generic Container