【问题标题】:Will move from unique to shared pointer also initialize enable_shared_from_this将从唯一指针移动到共享指针也初始化 enable_shared_from_this
【发布时间】:2018-12-18 14:09:52
【问题描述】:

当我从std::enable_shared_from_this 继承但我创建了一个unique_ptr 时,当我通过std::move 或移动构造函数“移动”到shared_ptr 时,std::enable_shared_from_this 内部的weak_ptr 是否也会被初始化?

例如下面的代码会发生什么:

#include <memory>
#include <iostream>

class A : public std::enable_shared_from_this< A >
{
public:
    std::shared_ptr< A > getA()
    {
        return shared_from_this();
    }
};

int main()
{
    std::unique_ptr< A > u(new A());
    // Aborts
    //std::cout << u->getA() << std::endl;
    std::shared_ptr< A > s(std::move(u));
    // Will this work or abort too?
    std::cout << s << ", " << s->getA() << std::endl;
}

【问题讨论】:

  • std::move 基本上是一个 noop,它没有任何作用。移动构造函数是唯一可以初始化对象的构造函数。
  • 我已经详细阐述了我的问题。我的意思是当我从一个weak_ptr 创建一个shared_ptr 时。它会初始化 std::enable_shared_from_this 基类吗?
  • minimal reproducible example 的形式显示您的代码示例。
  • 所以你有一个带有这个 shared_from_this 对象的 unique_ptr(这已经是一个错误,不是吗?)并且你从中创建了一个新的 shared_ptr,这没有意义,因为已经有一个 shared_pointer 和 shared_from_this .创建另一个是错误的。
  • 我添加了一些示例代码,这是否表明您的要求?

标签: c++ stl smart-pointers


【解决方案1】:

根据https://en.cppreference.com/w/cpp/memory/enable_shared_from_this,所有std::shared_ptr 构造函数都应该初始化内部弱引用,因此将std::unique_ptr 移动到std::shared_ptr 应该可以使用shared_from_this

您必须小心,当对象归 std::unique_ptr 所有时,没有人调用 shared_from_this,因为这要么是未定义的行为,要么会抛出 std::bad_weak_ptr,具体取决于您的 c++ 版本。

【讨论】:

    【解决方案2】:

    [util.smartptr.shared.const]/1 在下面的构造函数定义中,启用shared_from_thisp,对于p 类型的p 类型Y*,意味着如果Y 具有明确且可访问的基类,该基类是enable_shared_from_this (23.11.2.5) 的特化,则remove_cv_t&lt;Y&gt;* 应隐式转换为T*,并且构造函数评估语句:

    if (p != nullptr && p->weak_this.expired())
    p->weak_this = shared_ptr<remove_cv_t<Y>>(*this, const_cast<remove_cv_t<Y>*>(p));
    

    template <class Y, class D> shared_ptr(unique_ptr<Y, D>&& r);
    

    [util.smartptr.shared.const]/29 效果: ...相当于shared_ptr(r.release(), r.get_deleter())


    template<class Y, class D> shared_ptr(Y* p, D d);
    

    [util.smartptr.shared.const]/10 效果:构造一个拥有对象p和删除器dshared_ptr对象。当T 不是数组类型时,...启用shared_from_thisp

    所以是的,std::shared_ptr&lt; A &gt; s(std::move(u)); 确实会适当地初始化事物以使 shared_from_this 工作。

    【讨论】:

      【解决方案3】:

      正如 Alan 和 Igor 所指出的,只要构造了 std::shared_ptr&lt;&gt; 以保存从 std::enable_shared_from_this 公开派生的对象,就可以适当地设置实现 shared_from_this() 魔法的 std::weak_ptr&lt;&gt;。所以,是的,你的代码可以工作。

      但是,成员方法

      std::shared_ptr<A> A::getA()
      {
          return shared_from_this();
      }
      

      除非对象实际上由std::shared_ptr&lt;&gt; 管理,否则将调用UB(C++17 之前)。不幸的是,在 C++17 之前,无法从对象(A 类型)中判断它是否由共享指针管理,并且您无法轻松阻止此 UB。

      由于您实际上是使用std::unique_ptr&lt;&gt; 来管理您的对象,因此我建议不要从std::enable_shared_from_this 继承。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-12-03
        • 1970-01-01
        • 1970-01-01
        • 2016-11-09
        • 1970-01-01
        • 1970-01-01
        • 2011-04-10
        相关资源
        最近更新 更多