Smart Pointer

Shared Pointer (shared_ptr)

A shared pointer is a type of smart pointer in C++ that allows multiple pointers to share ownership of a dynamically allocated object.

Links:

Usage

#include <memory>
 
std::shared_ptr<B> p = std::make_shared<B>(arg1, arg2,...); 
shared_ptr<C> q = p; // Later

shared_ptr vs. unique_ptr?

Remember that unique_ptr represents ownership. https://stackoverflow.com/questions/6876751/differences-between-unique-ptr-and-shared-ptr

how is this implemented under the hood?

shared_ptr maintains a reference count, which keeps track of how many shared pointers point at this memory. When it hits 0, memory is freed.

So shared pointers have 2 fields:

  1. Pointer to the object
  2. Pointer to an integer storing the reference count

When you copy construct, these pointers are copied.

Consider the follow example:

{
	// replace ... with args to create a C object
	shared_ptr<C> p = make_shared<C>(...); 
	if (...) {
		shared_ptr<C> q = p;
	} // destructor for q runs, reference count is 1
	...
} // dtor for p runs, ref count is 0, C object is deleted

Is shared_ptr thread safe?

Thinking about this when thinking about how ROS2 is built. https://stackoverflow.com/questions/14482830/stdshared-ptr-thread-safety

Some Problems with shared_ptr

There are some problems with shared_ptrs, that you really need to be careful with.

  1. Susceptible if you use the constructor
C* cp = new C{...};
shared_ptr<C> p{cp}; // Incorrect
shared_ptr<C> q{cp}; // Double delete
  • q has no knowledge of p’s existence
  1. Cyclical reference issue
    • If we have multiple shared ptrs that point at each other, we have the issue that some pointers may never be deleted
class Node {
	shared_ptr<Edge> myEdges;
	shared_ptr<Node> neighbors;
}

full example through ChatGPT

class Node {
	public:
	    shared_ptr<Node> next;
};
 
int main() {
    shared_ptr<Node> node1 = make_shared<Node>();
    shared_ptr<Node> node2 = make_shared<Node>();
 
    // Create a cyclical reference
    node1->next = node2;
    node2->next = node1;
 
    return 0;
}

In general, shared ownership is somewhat rare. Take care in constructing your programs. Usually, it suffices to use the following:

  • unique_ptr or object field - ownership / Composition
  • raw pointer or reference - Aggregation (“has-a”)
  • shared_ptr - shared ownership

Exercise: Implement shared_ptr.

std::enable_shared_from_this

Stumbled upon this randomly while going through https://notes.sibeliusp.com/pdf/1189/cs246e.pdf.

If you want to get a shared_ptr to this, you can use std::enable_shared_from_this, see https://en.cppreference.com/w/cpp/memory/enable_shared_from_this

https://stackoverflow.com/questions/712279/what-is-the-usefulness-of-enable-shared-from-this

Serendipity: I saw this while looking at the way ROS has Node::SharedPtr https://answers.ros.org/question/353828/getting-a-nodesharedptr-from-this/