我的问题是关于这个主张:
如果任何std :: weak_ptr在所有共享所有者的生命周期结束后引用由std :: make_shared创建的控制块,则T占用的内存将持续存在,直到所有弱所有者都被销毁,如果sizeof(这可能是不合需要的) T)很大。 Source
我读了here,这个对象一直存在,直到最后一个weak_ptr存在。 它是使用make_shared制作的自由对象,循环引用自身还是永远存在于内存中?
例如:
struct A
{
std::weak_ptr<A> parent;
}
void fn()
{
auto a=std::make_shared<A>();
a->parent = a;
} // Will it destroy here or not?
答案 0 :(得分:11)
它被摧毁了。这是weak_ptr
存在的原因之一。
当a
被销毁时,引用计数器变为0,因此对象被销毁。这意味着调用对象的析构函数,它也会销毁a->parent
。
不要将销毁与 deallocation 混淆。当引用计数器变为0或者没有shared_ptr
拥有该对象时,该对象被销毁。如果有任何weak_ptr
指向控制块,则内存不会被解除分配 - 因为对象分配了std::make_shared
- 但对象肯定是< EM>破坏
答案 1 :(得分:3)
问题涉及:
如果任何std :: weak_ptr在所有共享所有者的生命周期结束后引用由std :: make_shared创建的控制块,则T占用的内存将持续存在,直到所有弱所有者都被销毁,如果sizeof(这可能是不合需要的) T)很大
就像是
#container h2:after {
transition: all 1s ease;
margin-left:5px;
}
#container:hover h2:after {
margin-left:25px;
transition: all 1s ease;
}
#container h2:after {
content: "->";
position: relative;
}
所以std::weak_ptr<A> global;
void foo()
{
auto a = std::make_shared<A>();
global = a;
}
指向global
的控制块。
即使a
被销毁,a
使用的内存仍然存在,以允许控制块存在。
答案 2 :(得分:0)
通过实现指针存在对象可达性循环,也就是说,您可以按照这些对象的私有实现中使用的指针进行操作,然后返回到您开始的位置:a->parent
包含指向由std::shared_ptr
或std::make_shared
创建的元信息(控制块)的指针。
当然std::make_shared
期望通过将元信息和托管对象放在一起来最小化动态内存分配的数量,但这与托管对象何时被销毁无关(这是唯一可观察的方面)因为没有使用特定类operator new
/ operator delete
。因此,无论控制块是与托管对象并置,还是指向单独分配的对象,都无关紧要。
除了少数退化情况之外(其中智能指针是使用不会释放任何内容的假删除器构建的),最后一个共享拥有智能指针的生命周期结束会导致删除程序运行,通常:
delete p;
形式的p
是T*
的构造函数std::shared_ptr<U>
的参数,p->~T()
形式,其中p
是new (buff) T
中std::make_shared<T>()
的结果。在任何一种情况下,都可以从元信息中获取p
的值。
[注意,永远不会从存储在任何特定p
实例中的U*
指针值获取要删除的值std::shared_ptr<U>
,因为这样的指针值可能不是“可删除的”,因为析构函数可能不是虚拟的(只要指针参数std::shared_ptr<U>
具有正确的静态类型:delete p;
就足够p
其中std::shared_ptr
是传递给模板化构造函数的类型的值),如果指针可能是成员子对象或完全不同的完整对象,如果使用别名构造函数构建另一个具有共享所有权的dynamic_cast
。]
所以有一个指向控制块的指针通常允许人们恢复指向受控对象的指针,尽管通过公共接口无法获得指向完整对象的指针(除了指针传递给删除器,所以只有这样才能在C ++中恢复指针,如果它丢失了,那就是通过一个自定义删除器并等待它被调用)。通过在内存表示中导航,当然可以恢复指针(尽管导航可能需要在编译时使用a
a->parent
parent->control_block
control_block.deleter (virtual call or stored function)
deleter.a
类型未知类型,只要它知道所有派生类,调试器就能做到这一点。 )。
所以我们有周期:
std::shared_ptr<U>(T*)
如果指针存储在动态创建的删除器中,则需要创建a
a->parent
parent->control_block
control_block.buffer
或
make_shared
对于使用单个分配&control_block.buffer == a
创建的对象:该对象是在该缓冲区内构建的{{1}}。
但是指针的循环不是问题,只是所有权的循环,因为它意味着“由生命控制的自我所有权”,即“只有当我的生命将结束时我才会毁灭自己”(又名“我将在进入析构函数时进入我将进入析构函数“),这是荒谬的。
此处没有所有权,因为弱引用只拥有元信息,而不是信息。