关于shared_from_this的问题

时间:2011-03-08 12:52:08

标签: c++ shared-ptr

我有一个shared_ptr<MyClass>的函数。 在memfun的某个成员函数MyClass中,我需要将this传递给该函数。但如果我写

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

我假设在通话结束后,引用计数将达到0并且将尝试销毁this,这是不好的。

然后我记得这个课程enable_shared_from_this的功能为shared_from_this

所以现在我将使用以下内容:

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

问题是:

1)如果不从enable_shared_from_this派生,绝对不可能使用该功能吗?     2)enable_shared_from_this派生是否意味着在具有自动存储持续时间的对象上调用memfun会导致错误? E.g。

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

3)如果我从MyClass派生,是否会正确继承enable_shared_from_this功能,还是需要再次派生?也就是说,

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

这样好吗?或者更正如下?

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

非常感谢。

5 个答案:

答案 0 :(得分:26)

1)这取决于你的意思是“做这个”你是否可以。您始终可以从原始指针(例如shared_ptr)构造this,但它不会与另一个从原始指针单独构造的shared_ptr实例共享引用计数。因此,您需要在一个或其他实例上使用自定义删除器以避免双重删除,但除非您非常小心,否则您可能最终会因为对象被删除而导致悬挂shared_ptr实例,但仍可访问来自另一个人。

shared_from_this使您可以保证,如果您的对象有一个shared_ptr实例,那么您可以构建另一个而不复制第一个实例,并且这些实例将共享引用计数。您可以通过将weak_ptr存储为类成员,并在第一次向对象分配shared_ptr时设置该值来实现此目的。

2)调用shared_from_this()要求至少有一个shared_ptr实例已指向您的对象。如果您在自动对象上使用它而没有带有自定义删除器的shared_ptr实例,那么您将收到不好的事情。

3)如果您派生自您的班级,那么enable_shared_from_this功能将为您提供shared_ptr基类(从enable_shared_from_this派生的基类)。然后,您可以使用static_pointer_castdynamic_pointer_castshared_from_this()的结果强制转换为指向派生类的指针。

答案 1 :(得分:11)

这里的重要问题是为什么函数通过shared_ptr获取参数。它是否在内部存储指针以供以后使用?它是否仅在通话期间使用它?为什么所有权在呼叫者和被呼叫者之间被稀释?

如果您要将堆栈分配的对象传递给函数,某些答案建议您提供no-op删除器,但如果该函数实际存储shared_ptr以供以后使用,则可能是这种情况当它到达它时,本地分配的对象不再在堆栈中并且您触发UB。拥有no-op删除器shared_ptr将允许调用,但语义将不正确。

如果该函数未存储shared_ptr供以后使用,那导致该API的设计决策是什么?如果您可以更改函数(并且没有迫在眉睫的原因),请让它通过引用接收参数,并且您将拥有一个友好的界面,不会无理由地强加shared_ptr

如果最后你确定你可以保证堆栈中的对象在该函数调用触发的整个过程中都处于活动状态,那么只能使用no-op deleter。

答案 2 :(得分:4)

1)不,没有shared_from_this这样做并非不可能。您只需使用no-op删除器构建shared_ptr

void do_nothing(MyClass*) {}

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

看来你实际上似乎并不需要shared_from_this,我将跳过你问题的下两部分。

答案 3 :(得分:2)

如果您有一个具有自动存储的对象和一个需要shared_ptr的函数,并且您知道对象的生命周期在函数持续时间内足够长并且它不会将shared_ptr存储在任何位置,那么您可以通过它带有无操作删除器。

这对静态对象很有用。如果它确实有本地自动存储,你需要问问自己为什么函数正在使用shared_ptr。它存储它们吗?

对于另一个引用计数对象的成员的对象,还有另一个鲜为人知的shared_ptr构造函数。实际上,您可以使用外部对象的shared_ptr和内部对象的指针创建shared_ptr。

答案 4 :(得分:-1)

除了DavidRodríguez - dribeas之外,google不建议使用共享指针

它在内部维护引用计数,因此使其正常工作,使用InterlockedIncrement和InterlockedDecrement,这两个函数实际上比普通的++和 - 慢。

您应该检查此对象所有权是否真的需要与他人共享,根据我的经验,在大多数情况下可以避免使用共享指针。