liveBook · Manning

Std::shared_ptr

As explained in 100 C++ Mistakes and How to Avoid Them

std::shared_ptr is a C++ standard-library smart pointer that maintains shared ownership of a dynamically allocated object through reference counting.

Mistake: using raw pointers when several parts of a structure share one dynamically allocated entity. A deque node may have multiple references, making deletion the developer’s responsibility at every possible exit and exception path. Missing one deletion leaks resources; duplicating ownership logic makes the data structure harder to understand and maintain. section 2.9

Listing 2.17 A deque using raw pointers
class Node {
public:
    Node(int value) : data(value), prev(NULL), next(NULL) {}
    int data;
    Node* prev;
    Node* next;
};
 
class Deque {
private:
    Node* front;
    Node* back;
public:
    Deque() : front(NULL), back(NULL) {}
    ~Deque() {                                       #1
        while (front != NULL) {
            Node* temp = front;
            front = front->next;
            delete temp;
        }
    }
    void push_front(int value) {
        Node* newNode = new Node(value);
        if (front == NULL)
            front = back = newNode;
        else {
            newNode->next = front;
            front->prev = newNode;
            front = newNode;
        }
    }
    void push_back(int value) {
        Node* newNode = new Node(value);
        if (back == NULL)
            front = back = newNode;
        else {
            newNode->prev = back;
            back->next = newNode;
            back = newNode;
        }
    }
    void pop_front() {
        if (front != NULL) {
            Node* temp = front;                       #2
            front = front->next;
            if (front != NULL)
                front->prev = NULL;
            else
                back = NULL;
            delete temp;                              #3
        }
    }
    void pop_back() {
        if (back != NULL) {
            Node* temp = back;                        #4
            back = back->prev;
            if (back != NULL)
                back->next = NULL;
            else
                front = NULL;
            delete temp;                              #5
        }
    }
};
 
int main() {
    Deque deque;
    deque.push_front(3);
    deque.pop_front();
    return 0;
}

The raw-pointer deque makes ownership visible through manual destructor logic and repeated delete decisions. Use it to locate the maintenance and exception-safety risks that shared ownership removes. section 2.9

Replace manual node ownership

Declare links and deque endpoints as std::shared_ptr<Node>, initialize empty pointers with nullptr, and create nodes with std::make_shared<Node>(value). Assigning the same node to front, back, prev, or next allows shared ownership while RAII releases the resource when its owners are gone. The deque no longer needs a destructor that walks the list and deletes nodes. section 2.9

Listing 2.18 A deque using shared pointers
class Node {
public:
    Node(int value) : data(value) {}
    int data;
    std::shared_ptr<Node> prev;                             #1
    std::shared_ptr<Node> next;                             #2
};
 
class Deque {
private:
    std::shared_ptr<Node> front;
    std::shared_ptr<Node> back;
public:
    Deque() : front(nullptr), back(nullptr) {}              #3
    void push_front(int value) {
        std::shared_ptr<Node> newNode = std::make_shared<Node>(value);
        if (front == nullptr)
            front = back = newNode;
        else {
            newNode->next = front;
            front->prev = newNode;
            front = newNode;
        }
    }
    void push_back(int value) {
        std::shared_ptr<Node> newNode = std::make_shared<Node>(value);
        if (back == nullptr)
            front = back = newNode;
        else {
            newNode->prev = back;
            back->next = newNode;
            back = newNode;
        }
    }
    void pop_front() {
        if (front != nullptr) {
            front = front->next;
            if (front != nullptr)
                front->prev = nullptr;
            else
                back = nullptr;
        }    #B
    }
    void pop_back() {
        if (back != nullptr) {
            back = back->prev;
            if (back != nullptr)
                back->next = nullptr;
            else
                front = nullptr;
        }                                                   #4
    }
};
 
int main() {
    Deque deque;
    deque.push_front(3);
    deque.pop_front();
    return 0;
}

The corrected deque shows the smallest practical migration: replace node pointer members and endpoints, use nullptr, and construct nodes with make_shared. section 2.9

Prefer std::shared_ptr when two or more references share a resource, and prefer std::make_shared over explicit new whenever possible. If modern C++ is unavailable, Boost supplies shared-pointer alternatives; avoid deprecated std::auto_ptr. section 2.9 section 10.6

How 100 C++ Mistakes and How to Avoid Them covers it

How deep it goes
Explains RAII-based shared ownership through deque member changes and deletion risks, without detailing pointer internals.
Examples
Uses a double-ended queue whose nodes link through shared_ptr, alongside raw-pointer and legacy smart-pointer resource examples.
What it assumes
Assumes basic pointers, dynamic allocation, and exceptions while teaching resource ownership through RAII.
What you can do after
Apply it via std::make_shared to replace raw-pointer ownership in shared-resource structures and reduce deletion code.
How it connects
Connects shared ownership with RAII, raw pointers, make_shared, unique_ptr, and Boost smart pointers.

Also explained in

Compare how 2 books explain std::shared_ptr →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of 100 C++ Mistakes and How to Avoid Them. The section links point to the parts of the book it draws on.