开发者

questions regarding shared_from_this

I have a function which takes a shared_ptr<MyClass>. In some member function memfun of MyClass, I need to pass this t开发者_如何转开发o 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.


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.


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.


1) No, it's not impossible to do this without shared_from_this. You can simply construct a shared_ptr with a no-op deleter:

void do_nothing(MyClass*) {}

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

Seeing as you don't actually seem to need shared_from_this after all, I'm going to skip the next two parts of your question.


If you have an object with automatic storage and a function that requires shared_ptr and you know that the lifetime of your object will be long enough for the duration of the function and that it does not store the shared_ptr anywhere, then you can pass it with a no-op deleter.

This is useful for static objects. If it really does have local automatic storage, you need to ask yourself why the function is taking shared_ptr. Does it store them?

There is another lesser-known constructor to shared_ptr for an object that is a member of another reference-counted object. You can actually create a shared_ptr with the shared_ptr from the outer object and the pointer from the inner object.


In addition with David Rodríguez - dribeas, shared pointer isn't recommended by google

It maintains reference count internally, so making it work correctly, InterlockedIncrement and InterlockedDecrement are used, these two functions are really slower than normal ++ and --.

You should check this object ownership truly need be shared with others, per my experience, shared pointer could be avoided in most cases.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜