Codementor Events

Smart Pointers in C++ - Part 4

Published Jun 28, 2021Last updated Jul 01, 2021
Smart Pointers in C++ - Part 4

Introduction

Welcome to Part #4 of Smart Pointers in C++!

The Parts #1, #2 and #3 are a prerquisite for Part #4 and can be found here

Let's learn more about shared_ptr.

Copy and move semantics of shared_ptr

We had mentioned in Part 2 that unique_ptr does not support copy semantics (copy constructor and copy assignment), it only supports move semantics (move constructor and move assignment). This is logical, as unique_ptr does not allow multiple owners of a single resource at any given time. So when a new smart unique pointer owns a resource, the old smart pointer has to be reset (it points to nullptr).

shared_ptr, on the other hand, supports both copy and move semantics.

Copy and move constructor

For shared_ptr there is a copy constructor and a move constructor defined in the class. The following code demonstrates the usage of both.

// create an int, make ptr1 the owner
std::shared_ptr<int> ptr1 (new int(10));

// make ptr2 an owner of the int created on previous line.
// now, both ptr1 and ptr2 own the int
std::shared_ptr<int> ptr2 (ptr1); // copy constructor

// create one more int, make ptr3 the owner
std::shared_ptr<int> ptr3 (new int(15));

// invalidate ptr3, ptr4 becomes the new owner
std::shared_ptr<int> ptr4 (std::move(ptr3)); // move constructor

std::cout << ptr1.use_count() << std::endl; // 2
std::cout << ptr2.use_count() << std::endl; // 2
std::cout << ptr3.use_count() << std::endl; // 0
std::cout << ptr4.use_count() << std::endl; // 1

use_count() is a member function of shared_ptr that returns the number of shared_ptr objects that share ownership of the resource owned by this pointer (including it). If it's an empty shared_ptr then zero (0) is returned.

In the above example, the first int has two shared pointers owners, viz. ptr1 and ptr2. That's the reason ptr1.use_count() and ptr2.use_count() both return 2. You will notice that ptr2 is constructed using a copy constructor.

Whereas, ptr3 is invalidated when ptr4 is constructed, as we have used a move constructor. So the int with value 15 has just one owner, ptr4. That's the reason ptr3.use_count() returns 0 and ptr4.use_count() returns 1.

Copy and move assignment

shared_ptr class also has a copy assignment and a move asignment defined for it. The following code demonstrates the usage of both.

std::shared_ptr<int> ptr1;
std::shared_ptr<int> ptr2 (new int(10));

ptr1 = ptr2; // copy assignment
// here, ptr1 and ptr2 both own the same int

ptr2 = std::make_shared<int> (20); // move assignment

std::cout << *ptr1 << std::endl; // 10
std::cout << *ptr2 << std::endl; // 20

make_shared() is a helper function that creates, in this example, an int and returns a shared_ptr to that int.

In the above excample, ptr1 is initially owning nothing. Then, ptr2 owns an int with value 10. The statement ptr1 = ptr2 is the copy assignment. ptr1 and ptr2 are both co-owning the same int with value 10.

Next, when the return value of make_shared is assigned to ptr2, the move assignment is at work. Why? That's because, std::make_shared<int> (20) creates a dying int. So instead of making a copy of that int and assigning the copy to ptr2, the compiler optimizes here and uses the move assignment.

Last, we use the overloaded dereference operator * to get the values pointed to by ptr1 and ptr2.

Follow this link to go to Part 5

Discover and read more posts from Sandesh Patil
get started