cpp make_shared 用于 void 指针
我想使用 std::make_shared 创建一个 void 指针。由于make_shared应该比shared_ptr(new T)更快,并且异常保存我想知道是否有一个库函数可以以make_shared方式创建shared_ptr(new foo)。
I would like to use std::make_shared to create a void pointer. Since make_shared is supposed to be faster than shared_ptr(new T), and exception save I wonder if there is a library function to create a shared_ptr(new foo) in the make_shared way.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
您可以将任何
shared_ptr
转换为shared_ptr
,而不会损失与make_shared
相关的效率:转换会保留
foo
和同一内存分配中的引用计数,即使您现在通过void*
引用它。更新
这是如何工作的?
std::shared_ptr
的一般结构是两个指针:p1
指向一个包含引用计数的控制块(实际上是两个引用计数:一个用于强所有者一个用于弱所有者)、一个删除器、一个分配器和一个指向对象“动态”类型的指针。 “动态”类型是shared_ptr
构造函数看到的对象类型,例如Y
(它可能与相同,也可能不同) T
)。p2
的类型为T*
,其中T
与shared_ptr< 中的
T
相同。 /代码>。将此视为存储对象的“静态”类型。当您取消引用shared_ptr
时,取消引用的是p2
。当您销毁shared_ptr
时,如果引用计数变为零,则控制块中的指针将有助于销毁foo
。在上图中,控制块和 foo 都是动态分配的。
p1
是一个拥有指针,控制块中的指针是一个拥有指针。p2
是一个非拥有指针。p2
的only 函数是取消引用(箭头运算符、get()
等)。当您使用
make_shared()
时,实现有机会将foo
与引用计数和其他数据一起放在控制块中:现在只有一个分配:现在嵌入
foo
的控制块。当上面的内容转换为
shared_ptr
时,会发生以下情况:即
p2
的类型从foo*
更改为无效*
。就是这样。 (除了增加/减少引用计数以考虑临时对象的复制和销毁之外,这可以通过从右值构造来消除)。当引用计数变为零时,它仍然是销毁通过p1
找到的foo
的控制块。p2
不参与销毁操作。p1
实际上指向控制块的通用基类。该基类不知道派生控制块中存储的类型foo
。当实际对象类型Y
已知时,派生控制块在shared_ptr
的构造函数中构造。但从那时起,shared_ptr
只能通过control_block_base*
与控制块通信。因此,诸如破坏之类的事情是通过虚拟函数调用发生的。C++11 中从右值
shared_ptr
进行shared_ptr
的“移动构造”只需复制两个内部指针,而不需要复制两个内部指针。来操纵引用计数。这是因为右值shared_ptr
无论如何都会消失:这可以在
shared_ptr
构造函数源代码中最清楚地看到:在转换构造之前,引用计数仅为 1。在转换构造之后,引用计数仍然为 1,源在其析构函数运行之前指向任何内容。简而言之,这就是移动语义的乐趣! :-)
You can convert any
shared_ptr<foo>
toshared_ptr<void>
without the loss of efficiency associated withmake_shared
:The conversion keeps the
foo
and the reference count in the same memory allocation, even though you now refer to it via avoid*
.Update
How does this work?
The general structure of a
std::shared_ptr<foo>
is two pointers:p1
points to a control block containing a reference count (actually two reference counts: one for strong owners and one for weak owners), a deleter, an allocator, and a pointer to the "dynamic" type of the object. The "dynamic" type is the type of the object that theshared_ptr<T>
constructor saw, sayY
(which may or may not be the same as aT
).p2
has typeT*
where theT
is the sameT
as inshared_ptr<T>
. Think of this as the "static" type of the stored object. When you dereference ashared_ptr<T>
, it isp2
that gets dereferenced. When you destruct ashared_ptr<T>
, and if the reference count goes to zero, it is the pointer in the control block that aids in the destruction offoo
.In the above diagram, both the control block and the
foo
are dynamically allocated.p1
is an owning pointer, and the pointer in the control block is an owning pointer.p2
is a non-owning pointer.p2
's only function is dereference (arrow operator,get()
, etc.).When you use
make_shared<foo>()
, the implementation has the opportunity to put thefoo
right in the control block, alongside of the reference counts and other data:The optimization here is that there is now only a single allocation: the control block which now embeds the
foo
.When the above gets converted to a
shared_ptr<void>
, all that happens is:I.e. The type of
p2
changes fromfoo*
tovoid*
. That's it. (besides incrementing/decrementing reference counts to account for a copy and destruction of a temporary -- which can be elided by construction from an rvalue). When the reference count goes to zero, it is still the control block that destroys thefoo
, found viap1
.p2
does not participate in the destruction operation.p1
actually points to a generic base class of the control block. This base class is ignorant of the typefoo
stored in the derived control block. The derived control block is constructed inshared_ptr
's constructor at the time the actual object typeY
is known. But from then on theshared_ptr
can only communicate with the control block via acontrol_block_base*
. So things like destruction happen via a virtual function call.The "move construction" of a
shared_ptr<void>
from an rvalueshared_ptr<foo>
in C++11 merely has to copy the two internal pointers, and does not have to manipulate the reference count. This is because the rvalueshared_ptr<foo>
is about to go away anyway:This can be seen most plainly in the
shared_ptr
constructor source code:Before the converting construction the reference count is only 1. And after the converting construction the reference count is still 1, with the source pointing to nothing just prior to its destructor running. This, in a nutshell, is the joy of move semantics! :-)