C++ shared_ptr (C++11)

beginner
24 min

C++ shared_ptr (C++11)

Welcome to our deep dive into the world of C++ smart pointers! Today, we'll explore one of the most useful and powerful smart pointers: shared_ptr.

What is a shared_ptr?

A shared_ptr is a smart pointer introduced in C++11 that keeps track of the number of shared owners of an object. It automatically deletes the object when the last owner goes out of scope.

cpp
#include <memory> // Declare a shared_ptr variable std::shared_ptr<int> myInt;

šŸ’” Pro Tip: The <memory> header provides all C++ smart pointers, including shared_ptr.

The Construction of shared_ptr

A shared_ptr can be constructed in several ways:

  1. Default Construction
cpp
std::shared_ptr<int> myInt; // Default constructs an empty shared_ptr
  1. Construct from a raw pointer
cpp
int data = 42; std::shared_ptr<int> myInt(new int(data)); // Constructs a shared_ptr from a raw pointer
  1. Construct from an existing shared_ptr
cpp
std::shared_ptr<int> anotherInt(std::make_shared<int>(42)); // Constructs a shared_ptr from an existing shared_ptr

šŸ“ Note: make_shared is a C++14 utility function that creates a shared_ptr with a specified type and initial value.

shared_ptr and Ownership

Each shared_ptr manages its own copy of the controlled object. When a shared_ptr is destroyed, it decrements the reference count of the controlled object. If the reference count reaches zero, the object is deleted.

cpp
std::shared_ptr<int> p1(new int(42)); std::shared_ptr<int> p2(p1); // p1 and p2 share ownership of the int

shared_ptr and Assignment

Assigning one shared_ptr to another does not transfer ownership. Instead, both pointers share the same controlled object:

cpp
std::shared_ptr<int> p1(new int(42)); std::shared_ptr<int> p2; p2 = p1; // p1 and p2 now share the same int

Managing shared_ptr Lifetime

In order to ensure that the controlled object is destroyed when no longer needed, you should create a shared_ptr in the scope that matches the lifetime of the object. For example:

cpp
{ std::shared_ptr<int> p(new int(42)); // Use p here... } // The shared_ptr is destroyed here, and the int is deleted

The use_count() and unique() Functions

The use_count() function returns the number of shared owners of the controlled object, while the unique() function ensures that the controlled object has a reference count of one.

cpp
std::shared_ptr<int> p1(new int(42)); std::shared_ptr<int> p2(p1); std::cout << p1.use_count() << std::endl; // Prints 2 p2.reset(); std::cout << p1.use_count() << std::endl; // Prints 1 p1.reset(); std::cout << p1.use_count() << std::endl; // Prints 0 p1.reset(new int(42)); p1.unique(); std::cout << p1.use_count() << std::endl; // Prints 1

Example: A Simple Shared Counter

Let's create a simple shared counter example to better understand the power of shared_ptr:

cpp
#include <iostream> #include <memory> #include <atomic> class SharedCounter { public: SharedCounter() : count_(new int(0)) {} void increment() { ++*count_; } int get_count() const { return *count_; } std::shared_ptr<SharedCounter> share() { return shared_from_this(); } private: std::shared_ptr<SharedCounter> shared_from_this() { return std::make_shared<SharedCounter>(*this); } std::shared_ptr<int> count_; };
Quick Quiz
Question 1 of 1

What happens when a `shared_ptr`'s controlled object is no longer needed?

int main() { SharedCounter counter;

std::shared_ptr<SharedCounter> p1(counter.share()); std::shared_ptr<SharedCounter> p2(counter.share()); p1->increment(); p2->increment(); std::cout << "Counter: " << counter.get_count() << std::endl; // Prints 2 // p1 and p2 share the same counter object p1->increment(); p2->decrement(); std::cout << "Counter: " << counter.get_count() << std::endl; // Prints 3 return 0;

}

In this example, we've created a `SharedCounter` class that can be shared using a `shared_ptr`. The `increment()` and `decrement()` functions modify the shared counter, while the `get_count()` function retrieves the current count. The `share()` function returns a new `shared_ptr` to the `SharedCounter`. That's it for today! You've learned the basics of C++ `shared_ptr`, including its construction, ownership management, and lifetime management. Next time, we'll delve into more advanced topics and examples using `shared_ptr`. Happy coding! šŸ¤–šŸš€