A circular reference occurs when objects refer to one another through shared pointers, eventually returning to an earlier object. The resulting ownership cycle can keep every reference count above zero, so the resources are never deleted. section 2.9
Mistake: shared ownership in both directions
A doubly linked structure can create the problem when each node stores both prev and next as std::shared_ptr values. One node owns the next node, while that node owns the previous node; after the surrounding deque is destroyed, the cycle may keep the nodes alive. Prefer unique ownership where sharing is unnecessary, and replace one ownership direction with a weak pointer when the links must point both ways. 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;
}
Inspect the shared-pointer deque and its bidirectional node links, which provide a concrete setting for identifying circular ownership. section 2.9


