Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

questions regarding shared_from_this

Tags:

I have a function which takes a shared_ptr<MyClass>. In some member function memfun of MyClass, I need to pass this to that function. But if I write

void MyClass:memfun() {    func(shared_ptr<MyClass>(this)) } 

I am assuming that after the call has ended the reference count will reach 0 and this will be attempted to be destroyed, which is bad.

Then I remembered that there this class enable_shared_from_this with the function shared_from_this.

So now I am going to use the following:

class MyClass: public enable_shared_from_this<MyClass> {     void MyClass:memfun()     {        func(shared_from_this());     } }; 

Questions are:

1) Is is absolutely impossible to use the functionality without deriving from enable_shared_from_this?
2) Does deriving from enable_shared_from_this mean that calling memfun on an object with automatic storage duration will result in something bad? E.g.

 int main()  {      MyClass m;   //is this OK?     m.memfun();  // what about this?  } 

3) If I derive from MyClass, will the enable_shared_from_this functionality be correctly inherited or do I need to derive again? That is,

class MyCoolClass: public Myclass {    void someCoolMember    {       someCoolFuncTakingSharedPtrToMyCoolClass(shared_from_this());    } } 

Is this OK? Or correct is the following?

 class MyCoolClass: public Myclass, public enable_shared_from_this<MyCoolClass>     {        void someCoolMember        {           someCoolFuncTakingSharedPtrToMyCoolClass(enable_shared_from_this<MyCoolClass>::shared_from_this());        }     }    

Thanks very much in advance.

like image 291
Armen Tsirunyan Avatar asked Mar 08 '11 12:03

Armen Tsirunyan


People also ask

Why shared_ from_ this?

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.

When to use shared_ from_ this?

The shared_from_this function searches for the existing control block rather than creating a new one. The simplest way to control this is to make the constructor private. Objects will be created using a static factory function that passes arguments to the private constructor.

How does Enable_shared_from_this work?

std::enable_shared_from_this is a standard solution that enables a shared_ptr managed object to acquire a shared_ptr to itself on demand. A class T that publicly inherits an std::enable_shared_from_this<T> encapsulates a std::weak_ptr<T> to itself that can be converted to a std::shared_ptr<T> when needed.

What is boost Enable_shared_from_this?

Purpose. The header <boost/enable_shared_from_this. hpp> defines the class template enable_shared_from_this. It is used as a base class that allows a shared_ptr to the current object to be obtained from within a member function.


2 Answers

1) It depends on what you mean by "do this" as to whether or not you can. You can always construct a shared_ptr from a raw pointer such as this, but it won't share the reference count with another shared_ptr instance that was separately constructed from a raw pointer. You will thus need to use a custom deleter on one or other instance to avoid double deletions, but unless you take great care then you may end up with dangling shared_ptr instances due to the object being deleted through one, but still accessible from another.

shared_from_this enables you to guarantee that if you have one shared_ptr instance to your object then you can construct another without copying the first, and that these instances will share the reference count. You could achieve this by storing a weak_ptr as a class member, and setting that value when you first allocate a shared_ptr to your object.

2) Calling shared_from_this() requires that there is at least one shared_ptr instance already pointing to your object. If you use it on an automatic object without a shared_ptr instance with a custom deleter then you will get bad stuff happening.

3) If you derive from your class then the enable_shared_from_this functionality will give you a shared_ptr to the base class (the one that derived from enable_shared_from_this). You could then use static_pointer_cast or dynamic_pointer_cast to cast the result of shared_from_this() to a pointer to the derived class.

like image 143
Anthony Williams Avatar answered Nov 08 '22 09:11

Anthony Williams


The important question here is why does the function take the argument through a shared_ptr. Does it store the pointer internally for later use? Does it only use it for the duration of the call? Why is the ownership diluted among the caller and the callee?

Some answers suggest that you provide a no-op deleter if you are going to pass a stack allocated object into the function, but if the function is actually storing the shared_ptr for later use, it might be the case that by the time it gets around to it, the locally allocated object is no longer in the stack and you trigger UB. Having the no-op deleter shared_ptr will allow the call, but the semantics will not be correct.

If the function does not store the shared_ptr for later use, what was the design decision that led to that API? If you can change the function (and there is no impending reason), make it receive the argument by reference and you will have a friendlier interface that does not impose a shared_ptr for no reason.

If at the end you determine that you can guarantee that the object in the stack will be alive for the whole duration of the process triggered by that function call, then and only then use the no-op deleter.

like image 41
David Rodríguez - dribeas Avatar answered Nov 08 '22 09:11

David Rodríguez - dribeas