通过实现指针有一个对象可达性的循环,也就是说,您可以跟随这些对象的私有实现内部使用的指针并返回到您开始的地方:a->parent
包含指向由std::shared_ptr
或创建的元信息(控制块)的指针由std::make_shared
.
当然std::make_shared
希望通过将元信息和托管对象放在一起来最小化动态内存分配的数量,但这与托管对象何时被销毁无关(这是唯一可观察到的方面,因为没有使用特定类operator new
/ operator delete
) . 因此,控制块是否与托管对象并置,或者是否具有指向该对象的单独分配的指针,是无关紧要的。
除了少数退化的情况(智能指针是用不释放任何东西的假删除器构造的),最后一个共享拥有智能指针的生命周期结束会导致删除器运行,通常:
- 要运行的形式
delete p;
,其中是构造函数p
类型的参数,T*
std::shared_ptr<U>
- or of the form
p->~T()
, where p
is the result of new (buff) T
in std::make_shared<T>()
.
In either case, the value of p
can be obtained from the meta information.
[Note that the value p
to be deleted is never obtained from the U*
pointer value stored in any particular std::shared_ptr<U>
instance, as such pointer value may not be "deletable", as the destructor may not be virtual (as long as the pointer argument std::shared_ptr<U>
has the right static type: it's sufficient that delete p;
where p
is the value of the type passed to the templated constructor), as the pointer may be to a member subobject or a complete different complete object, if an aliasing constructor was used to construct another std::shared_ptr
with shared ownership.]
So having a pointer to the control block usually allows one to recover a pointer to the controlled object, although that pointer to the complete object cannot be obtained through the public interface (except that the pointer is passed to the deleter, so the only way to recover the pointer in C++, if it was lost, would be to have passed a custom deleter and wait for it to be called). The pointer can certainly be recovered by navigating inside the memory representation (although that navigation might need to use dynamic_cast
to a type unknown at compile time, something the debugger will be able to do as long as it knows about all derived classes).
So we have the cycle:
a
a->parent
parent->control_block
control_block.deleter (virtual call or stored function)
deleter.a
if the pointer is stored in a dynamically created deleter, as is necessary to create std::shared_ptr<U>(T*)
, or
a
a->parent
parent->control_block
control_block.buffer
for objects created with a single allocation make_shared
: the object was constructed inside that buffer so &control_block.buffer == a
.
But cycles of pointers are not an issue, only cycle of ownership as it implies "self ownership controlled by lifetime", that is "I will destruct myself only when my lifetime will be over" (aka "I will enter destructor when I will have entered destructor"), an absurdity.
Here there is no ownership as a weak reference only owns the meta information, not the information.