c++ - 在同一个对象上创建多个 shared_ptr "families"时 shared_from_this 的意外行为

标签 c++ shared-ptr weak-ptr

下面是一些示例代码(在线 here ):

#include <memory>

struct Foo : public std::enable_shared_from_this<Foo> {};

void example()
{
    auto sharedFoo = std::make_shared<Foo>();
    std::shared_ptr<Foo> nonDeletingSharedFoo(sharedFoo.get(), [](void*){});
    nonDeletingSharedFoo.reset();
    sharedFoo->shared_from_this(); // throws std::bad_weak_ptr
}

我看到的(在多个编译器下)是当 nonDeletingSharedFoo 被重置时, enable_shared_from_this 内部使用的 weak_ptr 过期,所以后续调用 shared_from_this 失败。

我希望 nonDeletingSharedFoo 有一个完全独立于 sharedFoo 的引用计数,因为它是从原始指针构造的,但显然它仍然影响 的弱计数code>Foo 对象的内部 weak_ptr。我假设这是因为 shared_ptr 构造函数和/或析构函数在指向的类型实现 enable_shared_from_this 时做了一些特殊的事情。

那么这段代码是否违反了标准?是否有解决方案,或者只是不可能在实现 enable_shared_from_this 的对象上拥有多个 shared_ptr“系列”?

最佳答案

你在这里处于灰色地带:enable_shared_from_this 通常通过 shared_ptr 构造函数来实现,这些构造函数拥有指向从 enable_shared_from_this 派生的对象的原始指针的所有权 设置包含在对象内的 weak_ptr。因此,稍后对 shared_from_this() 的调用会返回一些内容。当您“重新设置”sharedFoo 时,原始的 weak_ptr 值将被覆盖,因此当您最终调用 shared_from_this 时它包含一个过期值。

标准可能禁止这种行为,但我认为更可能是允许这种行为的意图,并且在这个公认的小众案例中,所有权的语义有点不明确。该标准确实指出“创建唯一指针的 shared_ptr 构造函数可以检测 enable_shared_from_this 基的存在并将新创建的 shared_ptr 分配给它的__weak_this 成员。” ([util.smartptr.enab]/11)。尽管注释是非规范性的,但我认为它说明了标准的意图。

您可以通过创建一个不共享所有权但仍然指向 sharedFoo 的真正空的 shared_ptr 来完全避免该问题:

std::shared_ptr<Foo> nonDeletingSharedFoo(std::shared_ptr<Foo>(), sharedFoo.get());

这利用了“别名”构造函数:

template<class Y> shared_ptr(const shared_ptr<Y>& r, T* p) noexcept;

它创建一个与 r 共享所有权的 shared_ptr,在本例中是一个空的默认构造的 shared_ptr,并指向 p。结果是一个空的(非拥有的)shared_ptr,它指向与 sharedFoo 相同的对象。

您有责任确保此类非拥有指针在引用对象的生命周期结束后永远不会被解除引用。清理设计可能会更好,这样您要么真正共享所有权,要么使用原始指针而不是“非拥有 shared_ptr”技巧。

关于c++ - 在同一个对象上创建多个 shared_ptr "families"时 shared_from_this 的意外行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29259500/

相关文章:

python - 我有一个带有独特字母表的文档,我该如何翻译它?

c++ - 无法安装和定位 libsqlite3.a

C++0x 和 Friend 函数以及 boost::make_shared

c++ - The C++ Programming Language 中的弱指针示例

c++ - 在 shared_ptr 过期后定位 weak_ptr

c++ - weak_ptr 如何知道共享资源已过期?

c++ - 二叉堆的高效实现

c++ - 找到满足浮点不等式的最小整数

c++ - shared_ptr 类中 get() 成员的用途是什么?

c++ - 了解 Scott Meyers 的第三个 std::weak_ptr 示例