std::shared_ptr
(C++)
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:
- Pointer to the object
- 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_ptr
s, that you really need to be careful with.
- 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 ofp
’s existence
- 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/