在同一对象上创建多个shared_ptr“族”时shared_from_this的意外行为
Unexpected behavior from shared_from_this when creating multiple shared_ptr "families" over same object
下面是一些示例代码(在线在这里(:
#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
完全分开的引用计数,因为它是从原始指针构造的,但显然它仍然影响Foo
对象的内部weak_ptr
的弱计数。我认为这是因为当指向类型实现enable_shared_from_this
时,shared_ptr
构造函数和/或析构函数会做一些特殊的事情。
那么这个代码是否违反了标准呢?是否有解决方案,或者只是不可能在实现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(。尽管注释是非规范性的,但我认为它说明了标准的意图。
您可以通过创建一个真正空的shared_ptr
来完全避免这个问题,该不共享所有权,但仍指向sharedFoo
:
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"黑客。
当你使用 get from sharedFoo (sharedFoo.get((( 时,你会得到shared_ptr包含的地址。因此,nonDeletingSharedFoo无法访问shared_ptr,当您重置nonDeletingSharedFoo时,您将释放地址内存。所以 sharedFoo 的对象现在不存在了。
- 如何解决"invalid conversion from 'char' to 'const char*'"
- std::async from std::async in windows xp
- 引用 std::shared:ptr 以避免引用计数
- std::is_reference from std::any
- std::time_point from and to std::string
- "No suitable conversion function from 'std::string' to 'const char *' exists"
- std::chrono::time_point from std::string
- Visual accept std::string from std::byte iterator
- C++中链表的错误"Abort signal from abort(3) (sigabrt) "
- dopen():不以 root 身份运行时"failed to map segment from shared object"
- C++ 中的"template <typename From, typename Tag> struct Alias;"是什么?
- from std::vector to adept::avector
- qt get child (Callout) from QChart
- Webassembly from Javascript
- Generate boost::uuids::uuid from boost::compute::detail::sha
- 无法使用 libtool 将 -shared 参数传递给 g++
- 什么是"Reading unbounded stream from standard input (Memory Management)"的例子
- Calling C++ dll from python
- 为什么我会收到"invalid conversion from 'Queue*/Stack*' to 'int'"错误消息?
- std::chrono 在从 main 或 from 类方法使用时给出不同的值