std :: enable_shared_from_this:是否允许在析构函数中调用shared_from_this()?

Vio*_*ffe 11 c++ destructor shared-ptr weak-ptr c++11

#include <memory>
#include <iostream>

struct A : public std::enable_shared_from_this<A>
{
    ~A()
    {
        auto this_ptr = shared_from_this(); // std::bad_weak_ptr exception here. 
        std::cout << "this: " << this_ptr;
    }
};

int main()
{
    auto a = std::make_shared<A>();
    a.reset();
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

我打电话时遇到std::bad_weak_ptr异常shared_from_this().它是按设计的吗?是的,它可能是危险的,因为在析构函数返回后不能使用此指针,但我没有看到为什么在技术上不可能在此处获取指针的原因,因为共享指针对象显然仍然存在并且可以是用过的.有没有办法绕过这个,没有写我自己的enable_shared_from_this模拟(我宁愿做不到)?

Jon*_*ely 14

我没有看到为什么在技术上不可能在这里获得指针的原因,因为共享指针对象显然仍然存在并且可以使用.

有一个非常好的技术原因,为什么它不可能.

shared_ptr可能存在,但对于引用计数A对象已达到零,这就是为什么析构函数正在运行.一旦引用计数达到零,它就不能再次增加(否则你可能会得到一个shared_ptr指向运行其析构函数或已经被销毁的对象).

调用shared_from_this()尝试增加引用计数并返回shared_ptr与当前所有者共享所有权,但是您不能将计数器从0增加到1,因此它会失败.

这个非常特殊的情况下(在对象的析构函数内)你知道对象还没有完全被破坏,但是enable_shared_from_this<A>无法知道谁在调用shared_from_this()函数,所以无法知道它是在这个特定情况下发生的还是在在对象的析构函数之外的一些其他代码(例如,在析构函数之后将继续运行的另一个线程).

如果你能以某种方式使它适用于这个特定的情况,并且你得到一个shared_ptr<A>引用当前被销毁的对象,你可以将它提供shared_ptr给析构函数之外的存储它以供以后使用的东西.shared_ptr在对象被销毁之后,这将允许其他代码访问悬空.这将是shared_ptrweak_ptr类型系统的一个大漏洞.


Cas*_*sey 11

[util.smartptr.enab]/7描述了前提条件shared_from_this:

要求: enable_shared_from_this<T>应为可访问的基类T.*this应该是t类型对象的子对象T.至少应有一个拥有的shared_ptr实例.p&t[EMPH.添加]

由于您的对象正在被销毁,因此必须是没有shared_ptr它拥有它的情况.因此,您不能在shared_from_this不违反该要求的情况下进行调用,从而导致未定义的行为.