Menu
Coddy logo textTech

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 nullptr

shared_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 2

weak_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 icon

Challenge

Easy

Let'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 a Document class that represents a shareable document. It should have:
    • A private title attribute (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
  • main.cpp: Demonstrate all three smart pointer types by reading a document title from input, then:
    • Create a unique_ptr to a Document with the input title
    • Print "Unique owner: <title>"
    • Transfer ownership to another unique_ptr using std::move
    • Print "Ownership transferred"
    • Create a shared_ptr to a new Document with title "SharedDoc"
    • Create a second shared_ptr pointing to the same document
    • Print "Shared owners: <count>" using use_count()
    • Create a weak_ptr from one of the shared pointers
    • Use lock() to access the document through the weak pointer and print "Weak access: <title>"

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 nullptr

shared_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 2

weak_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;
}
quiz iconTest yourself

This lesson includes a short quiz. Start the lesson to answer it and track your progress.

All lessons in Object Oriented Programming