std::shared_ptr


Keyword: std::shared_ptr

std::shared_ptr is one of the most commonly used smart pointers in C++. It is a reference-counted smart pointer, meaning it keeps track of how many std::shared_ptr instances point to the same resource. The resource is automatically freed when the last std::shared_ptr pointing to it is destroyed or reset. This makes std::shared_ptr particularly useful when multiple parts of a program need to share ownership of a resource.

Key Characteristics of std::shared_ptr

Example 1: Basic Usage

#include <iostream>
#include <memory>

class MyClass {
public:
    MyClass() { std::cout << "MyClass Constructor" << std::endl; }
    ~MyClass() { std::cout << "MyClass Destructor" << std::endl; }
    void sayHello() const { std::cout << "Hello from MyClass" << std::endl; }
};

int main() {
    std::shared_ptr<MyClass> ptr1 = std::make_shared<MyClass>();  // Create a shared_ptr
    {
        std::shared_ptr<MyClass> ptr2 = ptr1;  // Share ownership with ptr2
        ptr2->sayHello();  // Use the object
        std::cout << "Reference count: " << ptr1.use_count() << std::endl;  // Outputs: 2
    }
    // ptr2 goes out of scope, reference count decreases
    std::cout << "Reference count: " << ptr1.use_count() << std::endl;  // Outputs: 1

    return 0;
}

Explanation:

Copying and Assignment

std::shared_ptr can be copied and assigned, unlike std::unique_ptr. Copying a std::shared_ptr increases the reference count, while assignment replaces the ownership of the shared_ptr.

Example2: Copying and Assignment

#include <iostream>
#include <memory>

class MyClass {
public:
    MyClass() { std::cout << "MyClass Constructor" << std::endl; }
    ~MyClass() { std::cout << "MyClass Destructor" << std::endl; }
};

int main() {
    std::shared_ptr<MyClass> ptr1 = std::make_shared<MyClass>();
    std::shared_ptr<MyClass> ptr2 = ptr1;  // Copy ptr1, reference count increases

    std::cout << "Reference count after copying: " << ptr1.use_count() << std::endl;  // Outputs: 2

    std::shared_ptr<MyClass> ptr3;
    ptr3 = ptr1;  // Assign ptr1 to ptr3, reference count remains the same

    std::cout << "Reference count after assignment: " << ptr1.use_count() << std::endl;  // Outputs: 3

    return 0;
}

Explanation:

Custom Deleters with std::shared_ptr

std::shared_ptr allows you to specify a custom deleter, which is a function or function object that is called when the last std::shared_ptr is destroyed and the resource is freed. This is useful for managing resources that require special cleanup, such as closing a file or freeing memory allocated in a non-standard way.

Example3: std::shared_ptr with a Custom Deleter

#include <iostream>
#include <memory>
#include <cstdio>  // For FILE*

struct FileDeleter {
    void operator()(FILE* fp) const {
        if (fp) {
            std::cout << "Closing file" << std::endl;
            std::fclose(fp);
        }
    }
};

int main() {
    std::shared_ptr<FILE> filePtr(std::fopen("example.txt", "w"), FileDeleter());

    if (filePtr) {
        std::fprintf(filePtr.get(), "Hello, file!\n");
    }

    // filePtr goes out of scope, and FileDeleter is invoked to close the file

    return 0;
}

Explanation:

Example4: Circular References

One potential issue with std::shared_ptr is circular references, where two or more shared_ptr instances reference each other. This can lead to memory leaks because the reference count never reaches zero, preventing the objects from being destroyed. To avoid this, std::weak_ptr can be used to break the cycle.

#include <iostream>
#include <memory>

class Node;

class Node {
public:
    std::shared_ptr<Node> next;
    std::shared_ptr<Node> prev;

    Node() { std::cout << "Node Constructor" << std::endl; }
    ~Node() { std::cout << "Node Destructor" << std::endl; }
};

int main() {
    std::shared_ptr<Node> node1 = std::make_shared<Node>();
    std::shared_ptr<Node> node2 = std::make_shared<Node>();

    node1->next = node2;  // node1 points to node2
    node2->prev = node1;  // node2 points back to node1

    // This creates a circular reference, preventing both nodes from being destroyed

    return 0;
}

Explanation:

Summary

std::shared_ptr is a powerful tool in modern C++ for managing shared ownership of resources, ensuring that they are automatically cleaned up when no longer needed, while also providing flexibility through custom deleters.

Previous Page | Course Schedule | Course Content