【问题标题】:Is this trick, to make calling shared_from_this() in the constructor 'just work', dangerous?这个技巧,在构造函数中调用 shared_from_this() '正常工作',危险吗?
【发布时间】:2016-01-09 06:09:05
【问题描述】:

C++ 专家的问题。

我们都知道在类构造函数中调用 shared_from_this() 会导致 bad_weak_ptr 异常,因为还没有创建实例的 shared_ptr。

为了解决这个问题,我想出了这个技巧:

class MyClass : public std::enable_shared_from_this<MyClass>
{
public:
    MyClass() {}

    MyClass( const MyClass& parent )
    {
        // Create a temporary shared pointer with a null-deleter
        // to prevent the instance from being destroyed when it
        // goes out of scope:
        auto ptr = std::shared_ptr<MyClass>( this, [](MyClass*){} );

        // We can now call shared_from_this() in the constructor:
        parent->addChild( shared_from_this() );
    }

    virtual ~MyClass() {}
};

有人认为这是不安全的,因为该物体尚未完全成型。他说的对吗?

我没有使用“this”来访问成员变量或函数。此外,只要我使用了初始化列表,所有成员变量都已经初始化。我不明白这个技巧怎么会不安全。

编辑:事实证明这个技巧确实会产生不必要的副作用。 shared_from_this() 将指向临时的shared_ptr,如果你不小心,我的示例代码中的父子关系将会中断。 enable_shared_from_this() 的实现根本不允许。谢谢,Sehe,为我指明了正确的方向。

【问题讨论】:

  • 使用静态工厂函数调用 make_shared 并进行添加可能会更好地处理。这种方式对正确性没有歧义。
  • 解决这个问题的一种方法是 MyClass temp(myparent); 局部变量刚刚被填充到共享指针中。
  • 这确实是我过去的处理方式(见下文),但我希望我能让它“正常工作”。 static std::shared_ptr&lt;MyClass&gt; create() { /* "initialize" would contain a call to shared_from_this() */ auto ptr = std::make_shared&lt;MyClass&gt;(); ptr-&gt;initialize(); return ptr; }

标签: c++ constructor this shared-ptr


【解决方案1】:

这并不危险。

记录的限制是:cppreference

在调用shared_from_this之前,至少应该有一个std::shared_ptrp拥有 *this

没有任何地方说它不能在构造函数内部使用/因此/。

这只是一个典型的。这是因为在正常情况下,make_sharedshared_pointer&lt;T&gt;(new T) 无法在 T 构造函数退出之前完成。

警告:该对象尚未完全形成,因此您不能合法调用任何虚拟方法(以Undefined Behaviour 为代价)。


指南 由于可能会错误地使用此类(例如,使用shared_ptr&lt;T&gt;(new T) 创建具有相同基础指针值的第二个shared_ptr...哎呀)您应该更喜欢防止这种情况的设计。

使用返回 shared_ptr&lt;T&gt; 的友元工厂函数可能是一种方法。

--> 参见The Pit Of Success

【讨论】:

  • 感谢您的解释。因此,如果我正确理解临时 shared_ptr 的技巧并不是危险的部分,那么如果 MyClass 将派生自某个基类并且将具有 MyClass::addChild( const MyClass&amp; child) override 函数,那么它就是调用 addChild 方法。您在指南部分中提到的有关拥有两个 shared_ptrs 的内容并没有真正发挥作用,因为第一个是临时的并且不会删除实例。
  • 是的。如果调用者不知道构造函数“种子”shared_from_this,它确实会发挥作用。最好避免这种可能性。
  • 现在措辞不同了:“特别是在*this的构造过程中不能调用shared_from_this
猜你喜欢
  • 2011-03-24
  • 1970-01-01
  • 1970-01-01
  • 2013-01-18
  • 1970-01-01
  • 2010-09-20
  • 1970-01-01
  • 2010-09-28
  • 1970-01-01
相关资源
最近更新 更多