I have been trying to understand the usefulness of inheriting from enable_shared_from_this
although the working of this mechanism was somewhat explained there. I couldn't find the answer to this question on that post so I am posting it here.
In one of the examples there. The following example was given as a bad practice. I understand the reason for that which is the two shared pointers dont know of each other and once one of the shared pointer goes out of scope the resource will be destroyed.
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;
}
My question is why did the user not do this
shared_ptr<S> sp2 = sp1;
Wouldn't that just increase the reference count as well ? and be fine ? Is that example given incase for some reason the class does not have access to sp1 and needs to return back a shared_ptr
?
The core problem is here, that not every shared pointer around in your code base is "known" to the rest of the code for some reason.
If you have access to a already given shared_ptr
you should always use shared_ptr<S> sp2 = sp1;
as you wrote. The is absolutely fine and better as using std::enable_shared_from_this
.
Lets take the following example:
struct S: std::enable_shared_from_this<S>
{
std::shared_ptr<S> getPtr() { return shared_from_this(); }
};
// Here we have no interface for providing a shared_ptr, maybe
// code that we can't change or maintain or comes as callback from
// a library we want to use
void f( S* s )
{
// here we have no access to shared_ptr<S>...
// so we need to have access to the unique counting instance
// of all other shared_ptr which are pointing to this object
std::shared_ptr<S> p3 = s->getPtr();
std::cout << p3.use_count() << std::endl;
// do some stuff....
}
int main()
{
std::shared_ptr<S> p1 = std::make_shared<S>();
std::cout << p1.use_count() << std::endl;
// This example is useless, as you can directly use p1
std::shared_ptr<S> p2 = p1->getPtr();
std::cout << p1.use_count() << std::endl;
std::cout << p2.use_count() << std::endl;
// But if we have to use a interface, which is not providing access via shared_ptr like this:
f(p1.get());
}
The key problem which is solved here is simply to get access to the common "handle" which is connecting all the other shared_ptr around in our system IF! we don't have access to any of the shared_ptr at all!
The reasons why we can't access any of the existing shared_ptr to our object can be many like: Use of old interfaces which only allow raw pointers but we want to use shared ptr in the rest of our code, using call backs from libraries which also only support raw pointers and so on.
Using std::enable_shared_from_this<S>
has some drawbacks:
Your interfaces can not use const S*
anymore, as creating a new shared_ptr
will modify the data of std::enable_shared_from_this
which is now a base class of your class or struct. Also it increases the size of your object.