Skip to main content

C Plus Plus

Mastering std::shared_ptr in C++

`std::shared_ptr` in C++ simplifies memory management by allowing multiple pointers to share ownership of an object. It automatically deallocates the object when no longer needed, reducing memory leaks and making code safer and cleaner.

In modern C++, managing dynamic memory and avoiding memory leaks is critical. One of the most powerful tools at your disposal for this task is std::shared_ptr. In this article, we'll explore what std::shared_ptr is, how it works, and provide examples to illustrate its usage.

Table of Contents

  1. Introduction
  2. Shared Ownership
  3. Cyclic Dependencies
  4. Custom Deleters
  5. std::shared_ptr with Arrays
  6. Implementing Shared Pointers in C++
  7. Conclusion

1 - Introduction

Introduction to std::shared_ptr in C++

std::shared_ptr is a smart pointer that facilitates shared ownership of dynamically allocated objects. Unlike raw pointers, it keeps track of how many std::shared_ptr instances share ownership of the same resource, and it automatically deallocates the resource when it's no longer needed. This feature makes std::shared_ptr a valuable asset for writing more reliable and memory-efficient C++ code.

Basic Usage:

Let's explore the fundamental aspects of std::shared_ptr with a simple code example:

#include <iostream>
#include <memory>

int main() {
    // Creating a shared pointer to an integer
    std::shared_ptr<int> sharedInt = std::make_shared<int>(42);

    // Accessing the value through the shared pointer
    std::cout << "Value: " << *sharedInt << std::endl;

    // Checking the reference count (number of shared_ptr instances)
    std::cout << "Reference count: " << sharedInt.use_count() << std::endl;

    // The shared pointer is automatically deallocated when it goes out of scope

    return 0;
}

In this example, we create a std::shared_ptr called sharedInt that manages a dynamically allocated integer with the value 42. We can safely access the integer using *sharedInt. The use_count() method tells us the reference count, which in this case, should be 1 since only one std::shared_ptr is currently managing the integer.

This is just the tip of the iceberg. std::shared_ptr offers advanced features like custom deleters, handling cyclic dependencies, and safe multi-threaded access, making it an invaluable tool for modern C++ development. In the subsequent sections, we will delve deeper into these aspects and explore real-world applications of std::shared_ptr.

2 - Shared Ownership

Shared Ownership with std::shared_ptr

std::shared_ptr is a smart pointer that enables shared ownership of dynamically allocated objects. It keeps track of how many std::shared_ptr instances share ownership of the same resource. The resource is automatically deallocated when the last std::shared_ptr that owns it goes out of scope. This feature simplifies memory management and helps prevent memory leaks.

Example of Shared Ownership:

Let's explore shared ownership using a comprehensive code example:

#include <iostream>
#include <memory>

class MyObject {
public:
    MyObject(int value) : data(value) {
        std::cout << "MyObject constructed with value " << data << std::endl;
    }

    ~MyObject() {
        std::cout << "MyObject destructed with value " << data << std::endl;
    }

    void print() {
        std::cout << "Value: " << data << std::endl;
    }

private:
    int data;
};

int main() {
    // Creating a shared pointer to a dynamically allocated object
    std::shared_ptr<MyObject> sharedObject = std::make_shared<MyObject>(42);

    // Creating another shared pointer that shares ownership
    std::shared_ptr<MyObject> anotherSharedObject = sharedObject;

    // Accessing the object's method through sharedObject
    sharedObject->print();

    // Accessing the object's method through anotherSharedObject
    anotherSharedObject->print();

    // Checking the reference count
    std::cout << "Reference count for sharedObject: " << sharedObject.use_count() << std::endl;
    std::cout << "Reference count for anotherSharedObject: " << anotherSharedObject.use_count() << std::endl;

    // sharedObject and anotherSharedObject go out of scope
    // The object is automatically deallocated when the last shared_ptr owning it goes out of scope

    return 0;
}

In this example, we create a class MyObject that has a constructor, a destructor, and a member function to print its value. We then use std::shared_ptr to manage an instance of MyObject. We also create another std::shared_ptr called anotherSharedObject that shares ownership of the same MyObject instance with sharedObject.