C++ base class with retain count - c++

I m writing a library.
WITHOUT using smart pointer. Is it this class safe enough to emulate retain/release behaviour?
Or is there any library already doing things like this?
class FooBase {
private:
std::atomic<uint32_t> m_retainCount;
public:
FooBase()
{
m_retainCount = 1;
};
virtual ~FooBase()
{
assert(m_retainCount == 0); // Prevent from direct delete without release()
//clean-up if any
};
void *release()
{
m_retainCount--;
if (!m_retainCount)
delete this;
return this;
};
void *retain()
{
m_retainCount++;
return this;
};
};

Imagine if your thread gets swapped right after the branch in release and before the call to delete.
Another thread could come and request a retain, therefore obtaining a pointer to a soon to be deleted object.

To answer the second part, std::shared_ptr is thread-safe. It has the additional benefit of being able to use non-portable tricks internally because it's formally part of the compiler.

Related

How to convert a this pointer to a std::shared_ptr? [duplicate]

I ran across enable_shared_from_this while reading the Boost.Asio examples and after reading the documentation I am still lost for how this should correctly be used. Can someone please give me an example and explanation of when using this class makes sense.
It enables you to get a valid shared_ptr instance to this, when all you have is this. Without it, you would have no way of getting a shared_ptr to this, unless you already had one as a member. This example from the boost documentation for enable_shared_from_this:
class Y: public enable_shared_from_this<Y>
{
public:
shared_ptr<Y> f()
{
return shared_from_this();
}
}
int main()
{
shared_ptr<Y> p(new Y);
shared_ptr<Y> q = p->f();
assert(p == q);
assert(!(p < q || q < p)); // p and q must share ownership
}
The method f() returns a valid shared_ptr, even though it had no member instance. Note that you cannot simply do this:
class Y: public enable_shared_from_this<Y>
{
public:
shared_ptr<Y> f()
{
return shared_ptr<Y>(this);
}
}
The shared pointer that this returned will have a different reference count from the "proper" one, and one of them will end up losing and holding a dangling reference when the object is deleted.
enable_shared_from_this has become part of C++ 11 standard. You can also get it from there as well as from boost.
from Dr Dobbs article on weak pointers, I think this example is easier to understand (source: http://drdobbs.com/cpp/184402026):
...code like this won't work correctly:
int *ip = new int;
shared_ptr<int> sp1(ip);
shared_ptr<int> sp2(ip);
Neither of the two shared_ptr objects knows about the other, so both will try to release the resource when they are destroyed. That usually leads to problems.
Similarly, if a member function needs a shared_ptr object that owns the object that it's being called on, it can't just create an object on the fly:
struct S
{
shared_ptr<S> dangerous()
{
return shared_ptr<S>(this); // don't do this!
}
};
int main()
{
shared_ptr<S> sp1(new S);
shared_ptr<S> sp2 = sp1->dangerous();
return 0;
}
This code has the same problem as the earlier example, although in a more subtle form. When it is constructed, the shared_ptr object sp1 owns the newly allocated resource. The code inside the member function S::dangerous doesn't know about that shared_ptr object, so the shared_ptr object that it returns is distinct from sp1. Copying the new shared_ptr object to sp2 doesn't help; when sp2 goes out of scope, it will release the resource, and when sp1 goes out of scope, it will release the resource again.
The way to avoid this problem is to use the class template enable_shared_from_this. The template takes one template type argument, which is the name of the class that defines the managed resource. That class must, in turn, be derived publicly from the template; like this:
struct S : enable_shared_from_this<S>
{
shared_ptr<S> not_dangerous()
{
return shared_from_this();
}
};
int main()
{
shared_ptr<S> sp1(new S);
shared_ptr<S> sp2 = sp1->not_dangerous();
return 0;
}
When you do this, keep in mind that the object on which you call shared_from_this must be owned by a shared_ptr object. This won't work:
int main()
{
S *p = new S;
shared_ptr<S> sp2 = p->not_dangerous(); // don't do this
}
Here's my explanation, from a nuts and bolts perspective (top answer didn't 'click' with me). *Note that this is the result of investigating the source for shared_ptr and enable_shared_from_this that comes with Visual Studio 2012. Perhaps other compilers implement enable_shared_from_this differently...*
enable_shared_from_this<T> adds a private weak_ptr<T> instance to T which holds the 'one true reference count' for the instance of T.
So, when you first create a shared_ptr<T> onto a new T*, that T*'s internal weak_ptr gets initialized with a refcount of 1. The new shared_ptr basically backs onto this weak_ptr.
T can then, in its methods, call shared_from_this to obtain an instance of shared_ptr<T> that backs onto the same internally stored reference count. This way, you always have one place where T*'s ref-count is stored rather than having multiple shared_ptr instances that don't know about each other, and each think they are the shared_ptr that is in charge of ref-counting T and deleting it when their ref-count reaches zero.
There is one particular case where I find enable_shared_from_this extremely useful: Thread safety when using asynchronous callback.
Imagine class Client has a member of type AsynchronousPeriodicTimer:
struct AsynchronousPeriodicTimer
{
// call this periodically on some thread...
void SetCallback(std::function<void(void)> callback);
void ClearCallback(); // clears the callback
}
struct Client
{
Client(std::shared_ptr< AsynchronousPeriodicTimer> timer)
: _timer(timer)
{
_timer->SetCallback(
[this]
()
{
assert(this); // what if 'this' is already dead because ~Client() has been called?
std::cout << ++_counter << '\n';
}
);
}
~Client()
{
// clearing the callback is not in sync with the timer, and can actually occur while the callback code is running
_timer->ClearCallback();
}
int _counter = 0;
std::shared_ptr< AsynchronousPeriodicTimer> _timer;
}
int main()
{
auto timer = std::make_shared<AsynchronousPeriodicTimer>();
{
auto client = std::make_shared<Client>(timer);
// .. some code
// client dies here, there is a race between the client callback and the client destructor
}
}
The client class subscribes a callback function to the periodic timer. Once the client object goes out of scope, there is a race condition between the client's callback and the client's destructor. The callback may be invoked with a dangling pointer!
The solution: using enable_shared_from_this to extend the object lifetime for the duration of the callback invocation.
struct Client : std::enable_shared_from_this<Client>
{
Client(std::shared_ptr< AsynchronousPeriodicTimer> timer)
: _timer(timer)
{
}
void Init()
{
auto captured_self = weak_from_this(); // weak_ptr to avoid cyclic references with shared_ptr
_timer->SetCallback(
[captured_self]
()
{
if (auto self = captured_self.lock())
{
// 'this' is guaranteed to be non-nullptr. we managed to promote captured_self to a shared_ptr
std::cout << ++self->_counter << '\n';
}
}
);
}
~Client()
{
// the destructor cannot be called while the callback is running. shared_ptr guarantees this
_timer->ClearCallback();
}
int _counter = 0;
std::shared_ptr< AsynchronousPeriodicTimer> _timer;
}
The mechanism of enable_shared_from_this, combined with the inherent thread safety of std::shared_ptr reference counting, enable us to ensure that the Client object cannot be destructed while the callback code is accessing its internal members.
Note that the Init method is separated from the constructor since the initialization process of enable_shared_from_this is not finalized until the constructor exits. Hence the extra method. It is generally unsafe to subscribe an asynchronous callback from within a constructor since the callback may access uninitialized fields.
Note that using a boost::intrusive_ptr does not suffer from this problem.
This is often a more convenient way to get around this issue.
It's exactly the same in c++11 and later: It is to enable the ability to return this as a shared pointer since this gives you a raw pointer.
in other word, it allows you to turn code like this
class Node {
public:
Node* getParent const() {
if (m_parent) {
return m_parent;
} else {
return this;
}
}
private:
Node * m_parent = nullptr;
};
into this:
class Node : std::enable_shared_from_this<Node> {
public:
std::shared_ptr<Node> getParent const() {
std::shared_ptr<Node> parent = m_parent.lock();
if (parent) {
return parent;
} else {
return shared_from_this();
}
}
private:
std::weak_ptr<Node> m_parent;
};

Uses of destructor = delete;

Consider the following class:
struct S { ~S() = delete; };
Shortly and for the purpose of the question: I cannot create instances of S like S s{}; for I could not destroy them.
As mentioned in the comments, I can still create an instance by doing S *s = new S;, but I cannot delete it as well.
Therefore, the only use I can see for a deleted destructor is something like this:
struct S {
~S() = delete;
static void f() { }
};
int main() {
S::f();
}
That is, define a class that exposes only a bunch of static functions and forbid any attempt to create an instance of that class.
What are the other uses (if any) of a deleted destructor?
If you have an object which should never, ever be deleted or stored on the stack (automatic storage), or stored as part of another object, =delete will prevent all of these.
struct Handle {
~Handle()=delete;
};
struct Data {
std::array<char,1024> buffer;
};
struct Bundle: Handle {
Data data;
};
using bundle_storage = std::aligned_storage_t<sizeof(Bundle), alignof(Bundle)>;
std::size_t bundle_count = 0;
std::array< bundle_storage, 1000 > global_bundles;
Handle* get_bundle() {
return new ((void*)global_bundles[bundle_count++]) Bundle();
}
void return_bundle( Handle* h ) {
Assert( h == (void*)global_bundles[bundle_count-1] );
--bundle_count;
}
char get_char( Handle const* h, std::size_t i ) {
return static_cast<Bundle*>(h).data[i];
}
void set_char( Handle const* h, std::size_t i, char c ) {
static_cast<Bundle*>(h).data[i] = c;
}
Here we have opaque Handles which may not be declared on the stack nor dynamically allocated. We have a system to get them from a known array.
I believe nothing above is undefined behavior; failing to destroy a Bundle is acceptable, as is creating a new one in its place.
And the interface doesn't have to expose how Bundle works. Just an opaque Handle.
Now this technique can be useful if other parts of the code need to know that all Handles are in that specific buffer, or their lifetime is tracked in specific ways. Possibly this could also be handled with private constructors and friend factory functions.
one scenario could be the prevention of wrong deallocation:
#include <stdlib.h>
struct S {
~S() = delete;
};
int main() {
S* obj= (S*) malloc(sizeof(S));
// correct
free(obj);
// error
delete obj;
return 0;
}
this is very rudimentary, but applies to any special allocation/deallocation-process (e.g. a factory)
a more 'c++'-style example
struct data {
//...
};
struct data_protected {
~data_protected() = delete;
data d;
};
struct data_factory {
~data_factory() {
for (data* d : data_container) {
// this is safe, because no one can call 'delete' on d
delete d;
}
}
data_protected* createData() {
data* d = new data();
data_container.push_back(d);
return (data_protected*)d;
}
std::vector<data*> data_container;
};
Why mark a destructor as delete?
To prevent the destructor from being invoked, of course ;)
What are the use cases?
I can see at least 3 different uses:
The class should never be instantiated; in this case I would also expect a deleted default constructor.
An instance of this class should be leaked; for example, a logging singleton instance
An instance of this class can only be created and disposed off by a specific mechanism; this could notably occur when using FFI
To illustrate the latter point, imagine a C interface:
struct Handle { /**/ };
Handle* xyz_create();
void xyz_dispose(Handle*);
In C++, you would want to wrap it in a unique_ptr to automate the release, but what if you accidentally write: unique_ptr<Handle>? It's a run-time disaster!
So instead, you can tweak the class definition:
struct Handle { /**/ ~Handle() = delete; };
and then the compiler will choke on unique_ptr<Handle> forcing you to correctly use unique_ptr<Handle, xyz_dispose> instead.
There are two plausible use cases. First (as some comments note) it could be acceptable to dynamically allocate objects, fail to delete them and allow the operating system to clean up at the end of the program.
Alternatively (and even more bizarre) you could allocate a buffer and create an object in it and then delete the buffer to recover the place but never prompt an attempt to call the destructor.
#include <iostream>
struct S {
const char* mx;
const char* getx(){return mx;}
S(const char* px) : mx(px) {}
~S() = delete;
};
int main() {
char *buffer=new char[sizeof(S)];
S *s=new(buffer) S("not deleting this...");//Constructs an object of type S in the buffer.
//Code that uses s...
std::cout<<s->getx()<<std::endl;
delete[] buffer;//release memory without requiring destructor call...
return 0;
}
None of these seems like a good idea except in specialist circumstances. If the automatically created destructor would do nothing (because the destructor of all members is trivial) then the compiler will create a no-effect destructor.
If the automatically created destructor would do something non-trivial you very likely compromise the validity of your program by failing to execute its semantics.
Letting a program leave main() and allowing the environment to 'clean-up' is a valid technique but best avoided unless constraints make it strictly necessary. At best it's a great way to mask genuine memory leaks!
I suspect the feature is present for completeness with the ability to delete other automatically generated members.
I would love to see a real practical use of this capability.
There is the notion of a static class (with no constructors) and so logically requiring no destructor. But such classes are more appropriately implemented as a namespace have no (good) place in modern C++ unless templated.
Creating an instance of an object with new and never deleting it is the safest way to implement a C++ Singleton, because it avoids any and all order-of-destruction issues. A typical example of this problem would be a "Logging" Singleton which is being accessed in the destructor of another Singleton class. Alexandrescu once devoted an entire section in his classical "Modern C++ Design" book on ways to cope with order-of-destruction issues in Singleton implementations.
A deleted destructor is nice to have so that even the Singleton class itself cannot accidentally delete the instance. It also prevents crazy usage like delete &SingletonClass::Instance() (if Instance() returns a reference, as it should; there is no reason for it to return a pointer).
At the end of the day, nothing of this is really noteworthy, though. And of course, you shouldn't use Singletons in the first place anyway.

shared_ptr and unique_ptr conversion

I'm in the situation where I'm not sure which type of smart pointer to use because I'm not sure of all the use cases for my class. I could just use shared pointers but I'm not fond of the idea of passing shared pointers everywhere in my code when I don't necessarily need shared ownership. This article by Herb Sutter says that when in doubt, use unique_ptr and convert to shared_ptr when you have to. This is what I'd like to do but I'm unclear as to how this is supposed to be done, consider this example:
class Example
{
public:
Example(): _ptr(std::make_unique<Node>()) {}
std::unique_ptr<Node>& getPtr()
{
return _ptr;
}
private:
// I am unsure if I will eventually need shared ownership or not
std::unique_ptr<Node> _ptr;
};
Example* example = new Example();
// Some function somewhere
void f()
{
// I've decided I need shared ownership, converting
std::shared_ptr<Node> ptr(std::move(example->getPtr()));
// Oops, example is no longer valid...
}
If someone has a better idea of how to deal with situations like this I'd be glad to hear it.
I think you are asking a kind of optimization question. You want Example to use unique_ptr because it has simpler and more efficient semantics (paraphrasing your referenced article). But, when the need arises, you wish to allow the pointer to be converted to shared_ptr.
Example should simply provide an interface for that, and itself needs to convert from unique_ptr to shared_ptr, when its user invokes that interface. You could use state pattern to capture whether the instance is in unique_ptr mode or shared_ptr mode.
class Example
{
struct StateUnique;
struct StateShared;
struct State {
State (std::unique_ptr<State> &s) : _state(s) {}
virtual ~State () = default;
virtual Node & getPtr () = 0;
virtual std::shared_ptr<Node> & getShared() = 0;
std::unique_ptr<State> &_state;
};
struct StateUnique : State {
StateUnique (std::unique_ptr<State> &s)
: State(s), _ptr(std::make_unique<Node>()) {}
Node & getPtr () { return *_ptr.get(); }
std::shared_ptr<Node> & getShared() {
_state = std::make_unique<StateShared>(*this);
return _state->getShared();
}
std::unique_ptr<Node> _ptr;
};
struct StateShared : State {
StateShared (StateUnique &u)
: State(u._state), _ptr(std::move(u._ptr)) {}
Node & getPtr () { return *_ptr.get(); }
std::shared_ptr<Node> & getShared() { return _ptr; }
std::shared_ptr<Node> _ptr;
};
public:
Example(): _state(std::make_unique<StateUnique>(_state)) {}
Node & getNode() { return _state->getPtr(); }
std::shared_ptr<Node> & getShared() { return _state->getShared(); }
private:
std::unique_ptr<State> _state;
};
If the state machine looks scary (which it should, since it is over-engineered), then you can just maintain two pointers in the Example, and your methods which need to test which one it needs to use.
class Example
{
public:
Example(): _u_node(std::make_unique<Node>()) {}
Node & getNode() { return _u_node ? *_u_node.get() : *_s_node.get(); }
std::shared_ptr<Node> & getShared() {
if (_u_node) _s_node = std::move(_u_node);
return _s_node;
}
private:
std::unique_ptr<Node> _u_node;
std::shared_ptr<Node> _s_node;
};
If you have a class, say UniqueResourceHolder, it may be implemented as follows:
class UniqueResourceHolder{
public:
std::unique_ptr<Widget> ptr;
};
Later, if you want to get said resource from UniqueResourceHolder and put it in a SharedResourceHolder that looks as follows:
class SharedResourceHolder{
public:
std::shared_ptr<Widget> ptr;
};
the code to do so may look like this:
{
UniqueResourceHolder urh;
SharedResourceHolder srh;
//initialization of urh.ptr
srh.ptr = std::shared_ptr<Widget>(urh.release());
}
UniqueResourceHolder will no longer have the Widget it once did, so any attempt to use urh to get at the widget will be invalid (unless you repopulate it with a new one), but srh now will have that widget and will be willing to share. Anyway, that's how I understand the answer to the question in the link you provided. My own two cents is that it is also a trivial matter to replace occurrences of std::unique_ptr with std::shared_ptr; any business logic your program followed to ensure the uniqueness of the resource is still valid, but to go from business logic where you took advantage of the shared-nature of std::shared_ptr would take some time and focus to rework to a unique mindset.
Shared pointers are for shared resources. If you want to share resources I would declare everything shared from the beginning and not go through special conversions.
If you want to use unique pointer you are saying that there "must" only exist one pointer for the the resource you have allocated. That does not limit your way in using these objects. Why not rather use unique pointer and "move" your object through the classes instances and functions... If you have to convert to your pointer why not move it as unique...
Regarding performance: It is said, that compared to a primite pointer, the shared pointer is about 6 times slower. The unique pointer is about twice as slow. Of course I'm talking about accesses. If you really have performance critical portions of the code you can still get primitive pointers of these classes and operate. It does not even have to be a pointer, there are still the C++ References.
I think you should decide whether your object will be "shared" or "moved" and go on with the paradigm, instead of converting and changing all the time.
std::unique_ptr<Node>& getPtr()
{
return _ptr;
}
No, no. You are passing multiple references if you call that from different places. Use the "move" operator instead (With declarations like type& operator=(type&& other) for example) and pass your unique pointer.

shared_ptr vs unique_ptr uses in classes and children

I've stared using smart pointer and trying to wrap my head around best uses for it. I've read plenty of articles but I'm confused on which to use in the following example. I've included a shared_ptr and unique_ptrexamples to show what I'm trying to accomplish:
class A
public:
A();
private:
unique_ptr<B> ptrB;
unique_ptr<SomeObject> ptrUnique;
shared_ptr<SomeObject> ptrShared;
A::A()
{
ptrB(new B());
ptrUnique(new SomeObject());
ptrB->PassUnique(ptrUnique);
ptrShared(new SomeObject());
ptrB->PassShared(ptrShared);
}
class B:
public:
void PassUnique(unique_ptr<SomeObject> &ptr_unique);
void PassShared(weak_ptr<SomeObject> &ptr_weak);
void DoSomething();
private:
unique_ptr<SomeObject> ptrUnique;
weak_ptr<SomeObject> ptrWeak;
B::PassUnique(unique_ptr<SomeObject> &ptr_unique)
{
ptrUnique = ptr_unique;
}
B::PassShared(weak_ptr<SomeObject> &ptr_weak)
{
ptrWeak = ptr_weak;
}
B::DoSomething()
{
ptrUnique->SomeMethod();
shared_ptr<SomeObject> ptr1 = ptrWeak.lock();
ptr1->SomeMethod();
}
SomeObject class can be any class. A good example is a database handle that I pass from the parent class A were it was originally initiated to multiple class like B. And from B to C if it exists. My question is if I'm passing a unique_ptr as a reference will setting for example ptrUnqiue = ptr_unique in B:PassUnique create a copy which then is not correct? Or should this be done via shared_ptr? This understanding is what is confusing with smart pointers for me and would appreciate clarification.
Well, this is a question of lifetime. Do you need SomeObject to outlive A? Do B send or is being use outside of this context? You have to decide when your objects dies. If you think SomeObject exists only in this context, I would recommend A to be the owner, as it allocate the resource, and be to old a raw pointer to SomeObject. I would look like this:
class A
public:
A();
private:
unique_ptr<B> ptrB;
unique_ptr<SomeObject> ptrUnique;
};
A::A()
{
ptrB(new B());
ptrUnique(new SomeObject());
ptrB->PassUnique(*ptrUnique);
}
class B:
pubic:
void PassUnique(SomeObject& obj);
void DoSomething();
private:
SomeObject* ptrUnique;
};
B::PassUnique(SomeObject& obj)
{
ptrUnique = &obj;
}
B::DoSomething()
{
ptrUnique->SomeMethod();
}
There is no such thing as
ptrUnique = ptr_unique;
If you need SomeObject to be used and owned outside of this structure, then go with std::shared_ptr like you did. There were no errors with your std::shared_ptr code.
Answer is basically what would be a lifetime of the pointer in the A, B and/or C. Think of it as ranges, [A...a), [B...b) and [C...c). If [B...b) is always within [A...a) and [C...c) is always within [B...b), they have like a Russian dolls hierarchy, then passing down ref-to-ptr is ok. If ranges overlap and changes wildly so you don't really control where last ptr will be destructed and object will be deleted, you'd have to go with shared_ptr.

What is the usefulness of `enable_shared_from_this`?

I ran across enable_shared_from_this while reading the Boost.Asio examples and after reading the documentation I am still lost for how this should correctly be used. Can someone please give me an example and explanation of when using this class makes sense.
It enables you to get a valid shared_ptr instance to this, when all you have is this. Without it, you would have no way of getting a shared_ptr to this, unless you already had one as a member. This example from the boost documentation for enable_shared_from_this:
class Y: public enable_shared_from_this<Y>
{
public:
shared_ptr<Y> f()
{
return shared_from_this();
}
}
int main()
{
shared_ptr<Y> p(new Y);
shared_ptr<Y> q = p->f();
assert(p == q);
assert(!(p < q || q < p)); // p and q must share ownership
}
The method f() returns a valid shared_ptr, even though it had no member instance. Note that you cannot simply do this:
class Y: public enable_shared_from_this<Y>
{
public:
shared_ptr<Y> f()
{
return shared_ptr<Y>(this);
}
}
The shared pointer that this returned will have a different reference count from the "proper" one, and one of them will end up losing and holding a dangling reference when the object is deleted.
enable_shared_from_this has become part of C++ 11 standard. You can also get it from there as well as from boost.
from Dr Dobbs article on weak pointers, I think this example is easier to understand (source: http://drdobbs.com/cpp/184402026):
...code like this won't work correctly:
int *ip = new int;
shared_ptr<int> sp1(ip);
shared_ptr<int> sp2(ip);
Neither of the two shared_ptr objects knows about the other, so both will try to release the resource when they are destroyed. That usually leads to problems.
Similarly, if a member function needs a shared_ptr object that owns the object that it's being called on, it can't just create an object on the fly:
struct S
{
shared_ptr<S> dangerous()
{
return shared_ptr<S>(this); // don't do this!
}
};
int main()
{
shared_ptr<S> sp1(new S);
shared_ptr<S> sp2 = sp1->dangerous();
return 0;
}
This code has the same problem as the earlier example, although in a more subtle form. When it is constructed, the shared_ptr object sp1 owns the newly allocated resource. The code inside the member function S::dangerous doesn't know about that shared_ptr object, so the shared_ptr object that it returns is distinct from sp1. Copying the new shared_ptr object to sp2 doesn't help; when sp2 goes out of scope, it will release the resource, and when sp1 goes out of scope, it will release the resource again.
The way to avoid this problem is to use the class template enable_shared_from_this. The template takes one template type argument, which is the name of the class that defines the managed resource. That class must, in turn, be derived publicly from the template; like this:
struct S : enable_shared_from_this<S>
{
shared_ptr<S> not_dangerous()
{
return shared_from_this();
}
};
int main()
{
shared_ptr<S> sp1(new S);
shared_ptr<S> sp2 = sp1->not_dangerous();
return 0;
}
When you do this, keep in mind that the object on which you call shared_from_this must be owned by a shared_ptr object. This won't work:
int main()
{
S *p = new S;
shared_ptr<S> sp2 = p->not_dangerous(); // don't do this
}
Here's my explanation, from a nuts and bolts perspective (top answer didn't 'click' with me). *Note that this is the result of investigating the source for shared_ptr and enable_shared_from_this that comes with Visual Studio 2012. Perhaps other compilers implement enable_shared_from_this differently...*
enable_shared_from_this<T> adds a private weak_ptr<T> instance to T which holds the 'one true reference count' for the instance of T.
So, when you first create a shared_ptr<T> onto a new T*, that T*'s internal weak_ptr gets initialized with a refcount of 1. The new shared_ptr basically backs onto this weak_ptr.
T can then, in its methods, call shared_from_this to obtain an instance of shared_ptr<T> that backs onto the same internally stored reference count. This way, you always have one place where T*'s ref-count is stored rather than having multiple shared_ptr instances that don't know about each other, and each think they are the shared_ptr that is in charge of ref-counting T and deleting it when their ref-count reaches zero.
There is one particular case where I find enable_shared_from_this extremely useful: Thread safety when using asynchronous callback.
Imagine class Client has a member of type AsynchronousPeriodicTimer:
struct AsynchronousPeriodicTimer
{
// call this periodically on some thread...
void SetCallback(std::function<void(void)> callback);
void ClearCallback(); // clears the callback
}
struct Client
{
Client(std::shared_ptr< AsynchronousPeriodicTimer> timer)
: _timer(timer)
{
_timer->SetCallback(
[this]
()
{
assert(this); // what if 'this' is already dead because ~Client() has been called?
std::cout << ++_counter << '\n';
}
);
}
~Client()
{
// clearing the callback is not in sync with the timer, and can actually occur while the callback code is running
_timer->ClearCallback();
}
int _counter = 0;
std::shared_ptr< AsynchronousPeriodicTimer> _timer;
}
int main()
{
auto timer = std::make_shared<AsynchronousPeriodicTimer>();
{
auto client = std::make_shared<Client>(timer);
// .. some code
// client dies here, there is a race between the client callback and the client destructor
}
}
The client class subscribes a callback function to the periodic timer. Once the client object goes out of scope, there is a race condition between the client's callback and the client's destructor. The callback may be invoked with a dangling pointer!
The solution: using enable_shared_from_this to extend the object lifetime for the duration of the callback invocation.
struct Client : std::enable_shared_from_this<Client>
{
Client(std::shared_ptr< AsynchronousPeriodicTimer> timer)
: _timer(timer)
{
}
void Init()
{
auto captured_self = weak_from_this(); // weak_ptr to avoid cyclic references with shared_ptr
_timer->SetCallback(
[captured_self]
()
{
if (auto self = captured_self.lock())
{
// 'this' is guaranteed to be non-nullptr. we managed to promote captured_self to a shared_ptr
std::cout << ++self->_counter << '\n';
}
}
);
}
~Client()
{
// the destructor cannot be called while the callback is running. shared_ptr guarantees this
_timer->ClearCallback();
}
int _counter = 0;
std::shared_ptr< AsynchronousPeriodicTimer> _timer;
}
The mechanism of enable_shared_from_this, combined with the inherent thread safety of std::shared_ptr reference counting, enable us to ensure that the Client object cannot be destructed while the callback code is accessing its internal members.
Note that the Init method is separated from the constructor since the initialization process of enable_shared_from_this is not finalized until the constructor exits. Hence the extra method. It is generally unsafe to subscribe an asynchronous callback from within a constructor since the callback may access uninitialized fields.
Note that using a boost::intrusive_ptr does not suffer from this problem.
This is often a more convenient way to get around this issue.
It's exactly the same in c++11 and later: It is to enable the ability to return this as a shared pointer since this gives you a raw pointer.
in other word, it allows you to turn code like this
class Node {
public:
Node* getParent const() {
if (m_parent) {
return m_parent;
} else {
return this;
}
}
private:
Node * m_parent = nullptr;
};
into this:
class Node : std::enable_shared_from_this<Node> {
public:
std::shared_ptr<Node> getParent const() {
std::shared_ptr<Node> parent = m_parent.lock();
if (parent) {
return parent;
} else {
return shared_from_this();
}
}
private:
std::weak_ptr<Node> m_parent;
};