智能指针控制块内部机械
Smart pointers' control block internal machinery
我想知道释放为 shared_ptr 和 weak_ptr 共享的内部控制块分配的内存的确切条件是什么。
我猜控制块包含一个 shared_ptr 计数器和一个 weak_ptr 计数器。
#include <memory>
#include <iostream>
struct Dummy
{
Dummy() { std::cout << "ctor" << std::endl; }
~Dummy() { std::cout << "dtor" << std::endl; }
};
int main()
{
auto dummy = new Dummy();
auto wp = std::weak_ptr<Dummy>(); // pointing to nothing
{
auto sp = std::shared_ptr<Dummy>(dummy); // 1
wp = sp; // 2
} // 3
std::cout << "Land mark" << std::endl;
}
- 使用虚拟分配的内存构建 shared_ptr。分配控制块,并将其虚拟指针设置为 "dummy"
- 从 shared_ptr 构建 weak_ptr。两个智能指针共享相同的控制块地址。
- 共享指针被破坏。调用虚拟 dtor("dtor" 在 "Land mark" 之前打印)。控制块仍然存在,直到程序结束。
我对这些评论是否正确?
在这些步骤中控制块内发生了什么(详细)?
编辑:make_shared 案例会怎样?
有一个分配包含虚拟对象和控制块。
这是否涉及新放置以使用两个不同的对象?
还是包含原始对象的结构?
#include <memory>
#include <iostream>
struct Dummy
{
Dummy() { std::cout << "ctor" << std::endl; }
~Dummy() { std::cout << "dtor" << std::endl; }
};
int main()
{
auto wp = std::weak_ptr<Dummy>(); // pointing to nothing
{
auto sp = std::make_shared<Dummy>();
wp = sp;
}
}
是的,你是对的。
详细情况:
- 控制块已创建并绑定到
share_ptr
。 shared_count = 1
, weak_count = 0
.
-
weak_pointer
绑定到控制块。 shared_count = 1
, weak_count = 1
.
- 最后(仅)
shared_pointer
死亡,对象被摧毁。控制块由 weak_ptr
维护。 shared_count = 0
, weak_count = 1
.
- (end of
main()
) 最后(仅)weak_ptr
死亡,shared_count = 0
。没有人再绑定到控制块,所以最后 weak_ptr
销毁控制块。
这是 valgrind massif 为您的测试显示的内容,(如果您不习惯 valgrind)这是按时间分配的内存量,首先是指向的对象,然后是计数管理器,然后是指向的对象被取消分配
这基本上就是它的工作原理,当最后一个 shared_ptr 超出范围时,指向的对象被删除(它的内存被释放),但是计数管理器仍然存在,因为 weak_ptr 需要知道发生了什么,是否有指向对象。
然而有时情况并非如此,如果你使用make_shared
,make_shared
实际上只为对象和计数管理器使用一个分配,在这种情况下,分配的内存将保留直到最后一个 weak_ptr 超出范围
我想知道释放为 shared_ptr 和 weak_ptr 共享的内部控制块分配的内存的确切条件是什么。
我猜控制块包含一个 shared_ptr 计数器和一个 weak_ptr 计数器。
#include <memory>
#include <iostream>
struct Dummy
{
Dummy() { std::cout << "ctor" << std::endl; }
~Dummy() { std::cout << "dtor" << std::endl; }
};
int main()
{
auto dummy = new Dummy();
auto wp = std::weak_ptr<Dummy>(); // pointing to nothing
{
auto sp = std::shared_ptr<Dummy>(dummy); // 1
wp = sp; // 2
} // 3
std::cout << "Land mark" << std::endl;
}
- 使用虚拟分配的内存构建 shared_ptr。分配控制块,并将其虚拟指针设置为 "dummy"
- 从 shared_ptr 构建 weak_ptr。两个智能指针共享相同的控制块地址。
- 共享指针被破坏。调用虚拟 dtor("dtor" 在 "Land mark" 之前打印)。控制块仍然存在,直到程序结束。
我对这些评论是否正确?
在这些步骤中控制块内发生了什么(详细)?
编辑:make_shared 案例会怎样?
有一个分配包含虚拟对象和控制块。
这是否涉及新放置以使用两个不同的对象?
还是包含原始对象的结构?
#include <memory>
#include <iostream>
struct Dummy
{
Dummy() { std::cout << "ctor" << std::endl; }
~Dummy() { std::cout << "dtor" << std::endl; }
};
int main()
{
auto wp = std::weak_ptr<Dummy>(); // pointing to nothing
{
auto sp = std::make_shared<Dummy>();
wp = sp;
}
}
是的,你是对的。
详细情况:
- 控制块已创建并绑定到
share_ptr
。shared_count = 1
,weak_count = 0
. -
weak_pointer
绑定到控制块。shared_count = 1
,weak_count = 1
. - 最后(仅)
shared_pointer
死亡,对象被摧毁。控制块由weak_ptr
维护。shared_count = 0
,weak_count = 1
. - (end of
main()
) 最后(仅)weak_ptr
死亡,shared_count = 0
。没有人再绑定到控制块,所以最后weak_ptr
销毁控制块。
这是 valgrind massif 为您的测试显示的内容,(如果您不习惯 valgrind)这是按时间分配的内存量,首先是指向的对象,然后是计数管理器,然后是指向的对象被取消分配
这基本上就是它的工作原理,当最后一个 shared_ptr 超出范围时,指向的对象被删除(它的内存被释放),但是计数管理器仍然存在,因为 weak_ptr 需要知道发生了什么,是否有指向对象。
然而有时情况并非如此,如果你使用make_shared
,make_shared
实际上只为对象和计数管理器使用一个分配,在这种情况下,分配的内存将保留直到最后一个 weak_ptr 超出范围