将从唯一指针移动到共享指针也会初始化 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
。
当我继承自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
withp
, for a pointerp
of typeY*
, means that ifY
has an unambiguous and accessible base class that is a specialization ofenable_shared_from_this
(23.11.2.5), thenremove_cv_t<Y>*
shall be implicitly convertible toT*
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 objectp
and the deleterd
. WhenT
is not an array type, ... enableshared_from_this
withp
所以是的,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
。