将从唯一指针移动到共享指针也会初始化 enable_shared_from_this

Will move from unique to shared pointer also initialize enable_shared_from_this

当我继承自std::enable_shared_from_this,但我创建了一个unique_ptr,当我"move"为a时,std::enable_shared_from_this里面的weak_ptr是否也会被初始化shared_ptr 通过 std::move,或者通过移动构造函数?

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

#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;
}

根据 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++ 版本。

[util.smartptr.shared.const]/1 In the constructor definitions below, enables shared_from_this with p, for a pointer p of type Y*, means that if Y has an unambiguous and accessible base class that is a specialization of enable_shared_from_this (23.11.2.5), then remove_cv_t<Y>* shall be implicitly convertible to T* and the constructor evaluates the statement:

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 Effects: ... equivalent to shared_ptr(r.release(), r.get_deleter())


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

[util.smartptr.shared.const]/10 Effects: Constructs a shared_ptr object that owns the object p and the deleter d. When T is not an array type, ... enable shared_from_this with p

所以是的,std::shared_ptr< A > s(std::move(u)); 会适当地初始化一些东西以使 shared_from_this 工作。

正如 Alan 和 Igor 所指出的,每当构建 std::shared_ptr<> 以持有从 std::enable_shared_from_this 公开派生的对象时,实施 shared_from_this() 魔法的 std::weak_ptr<> 就会被适当地设置.所以,是的,你的代码可以工作。

但是,成员方法

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

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

由于您实际使用 std::unique_ptr<> 来管理您的对象,因此我建议不要继承自 std::enable_shared_from_this