【发布时间】:2019-06-05 17:44:12
【问题描述】:
有几个问题涵盖了std::enable_shared_from_this 的行为,但我不认为这是重复的。
从std::enable_shared_from_this 继承的类带有std::weak_ptr 成员。当应用程序创建一个指向std::enable_shared_from_this 子类的std::shared_ptr 时,std::shared_ptr 构造函数会检查std::weak_ptr,如果它没有被初始化,则初始化它并使用std::weak_ptr 控制块来控制std::shared_ptr .但是,如果 std::weak_ptr 已经初始化,构造函数只会创建一个带有新控制块的新 std::shared_ptr。当两个std::shared_ptr 实例之一的引用计数变为零并删除底层对象时,这会使应用程序崩溃。
struct C : std::enable_shared_from_this<C> {};
C *p = new C();
std::shared_ptr<C> p1(p);
// Okay, p1 and p2 both have ref count = 2
std::shared_ptr<C> p2 = p->shared_from_this();
// Bad: p3 has ref count 1, and C will be deleted twice
std::shared_ptr<C> p3(p);
我的问题是:为什么图书馆会这样?如果std::shared_ptr 构造函数知道该对象是std::enable_shared_from_this 子类并费心检查std::weak_ptr 字段,为什么它不总是为新的std::shared_ptr 使用相同的控制块,从而避免潜在的崩溃?
那么,为什么 shared_from_this 方法在 std::weak_ptr 成员未初始化时会失败,而不是仅仅初始化它并返回 std::shared_ptr?
这个库的工作方式似乎很奇怪,因为它在很容易成功的情况下失败了。我想知道是否有我不理解的设计注意事项/限制。
我在 C++17 模式下使用 Clang 8.0.0。
【问题讨论】:
-
对于第二个问题,初始化一个新的
std::shared_ptr而不是在shared_from_this上失败,您不能假设当前是如何管理对象的生命周期的。除非它由用户不会delete的原始指针拥有,否则实际上不会有任何好的结果。例如,如果我尝试使用自动存储持续时间的shared_from_this会发生什么? -
the std::shared_ptr constructor checks the std::weak_ptr, and if it is not initialized, initializes it and uses the std::weak_ptr control block for the std::shared_ptr我不认为这是准确的。 cppreference 声明weak_ptr已初始化值。我认为这意味着没有进行检查。因此,添加检查会增加每个不需要检查的构造的成本。 -
@FrançoisAndrieux 在关于对象的观点上足够公平,没有假设
this是一个可以/应该从中创建共享指针的指针。 -
拥有多个指向“同一个对象”的智能指针(无论这意味着什么)本质上并不是一个坏主意。
标签: c++ c++17 shared-ptr weak-ptr enable-shared-from-this