我的类继承自多个基,其中一个是std::enable_shared_from_this
。一定是一垒吗?
假设以下示例代码:
struct A { ~A(); };
struct B { ~B(); };
struct C : A, B, std::enable_shared_from_this<C> {};
std::make_shared<C>();
当~A()
和~B()
运行时,我能确定C
所在的存储器仍然存在吗?
当~A((和~B((运行时,我能确定C所在的存储仍然存在吗?
否,基类的顺序无关紧要。即使是enable_shared_from_this的使用(或不使用(也是不重要的。
当一个C对象被破坏时(不管发生什么(,~C()
将在~A()
和~B()
之前被调用,因为这是基本析构函数的工作方式。如果您试图在基析构函数和其中的访问字段中"重建"C对象,那么这些字段将已经被销毁,因此您将获得未定义的行为。
当
~A()
和~B()
运行时,我可以确定C
所在的存储是否仍然存在?
当然!很难使用一个试图释放自己内存(它所在的内存(的基类。我甚至不确定它是否正式合法。
实现并没有做到这一点:当shared_ptr<T>
被破坏或重置时,T
的共享所有权的引用计数(RC(会减少(原子(;如果它在递减中达到0,则开始销毁/删除T
。
然后,当T
不再存在时,weak-owners-or-T-exists计数(原子地(递减:我们需要知道我们是否是对控制块感兴趣的最后一个实体;如果减量给出非零结果,则意味着一些weak_ptr
存在控制块的共享(可以是1共享,或100%(所有权,并且它们现在负责解除分配。
无论哪种方式,对于最后一个共同所有者,原子递减率在某个时刻都将为零值。
这里没有线程,没有非确定性,显然最后一个weak_ptr<T>
是在C
的销毁过程中销毁的。(你的问题中不成文的假设是没有保留其他weak_ptr<T>
。(
破坏总是按照的精确顺序发生控制块用于销毁,因为shared_ptr<T>
(通常(不知道(可能不同的(派生类的哪个(可能非虚拟的(销毁函数要调用。(控制块也知道不在make_shared
的共享计数达到零时释放内存。(
实现之间唯一实际的变化似乎是关于内存围栏的精细细节,以及在常见情况下避免一些原子操作。
如果通过从基enable_shared_from_this<T>
继承创建一个c类型的对象c,该对象具有基A、B和一个引用计数器,那么首先会为整个生成的对象分配内存,包括一般的基和基enable_shared_from_this<T>
。直到最后一个所有者(也称为shared_ptr(放弃所有权,对象才会被销毁。那一刻~enable_shared~B和~A将在~C之后运行。在最后一个析构函数~A运行之前,完全分配的内存仍然保证在那里。运行~A之后,整个对象内存将被一下子释放。因此,为了回答您的问题:
当~A((和~B((运行时,我能确定C所在的存储仍然存在吗?
是的,尽管你不能合法访问它,但你为什么需要知道?你想避免哪个问题?