cpp make_shared用于void指针

时间:2011-12-27 14:40:19

标签: c++ c++11 smart-pointers

我想使用std :: make_shared来创建一个void指针。因为make_shared应该比shared_ptr(new T)快,并且异常保存我想知道是否有一个库函数以make_shared方式创建shared_ptr(new foo)。

1 个答案:

答案 0 :(得分:14)

您可以将shared_ptr<foo>转换为shared_ptr<void>而不会降低与make_shared相关的效率:

#include <memory>

struct foo {};

int main()
{
    std::shared_ptr<void> p = std::make_shared<foo>();
}

转换会将foo和引用计数保持在相同的内存分配中,即使您现在通过void*引用它。

<强>更新

这是如何运作的?

std::shared_ptr<foo>的一般结构是两个指针:

                          +------> foo
                          |         ^
p1  ---------> (refcount, +)        |
p2  --- foo* -----------------------+

p1指向一个包含引用计数的控制块(实际上有两个引用计数:一个用于强所有者,一个用于弱所有者),一个删除器,一个分配器和一个指向“动态”类型的指针物体。 “动态”类型是shared_ptr<T>构造函数看到的对象的类型,例如Y(可能与T相同或不同)。

p2的类型为T*,其中TT中的shared_ptr<T>相同。可以将其视为存储对象的“静态”类型。取消引用shared_ptr<T>时,取消引用p2。当你破坏shared_ptr<T>时,如果引用计数变为零,则控制块中的指针有助于销毁foo

在上图中,控制块和foo都是动态分配的。 p1是拥有指针,控制块中的指针是拥有指针。 p2是非拥有指针。 p2唯一功能是取消引用(箭头操作符,get()等)。

当您使用make_shared<foo>()时,实现有机会将foo权限放在控制块中,与引用计数和其他数据一起:

p1  ---------> (refcount, foo)
p2  --- foo* --------------^

这里的优化是现在只有一个分配:控制块现在嵌入foo

当上述内容转换为shared_ptr<void>时,所发生的一切都是:

p1  ---------> (refcount, foo)
p2  --- void* -------------^

即。 p2的类型从foo*更改为void*。而已。 (除了递增/递减引用计数以考虑临时的复制和销毁 - 可以通过构造来从rvalue中省略)。当引用计数变为零时,它仍然是破坏通过foo找到的p1的控制块。 p2不参与销毁行动。

p1实际上指向控制块的通用基类。此基类不知道存储在派生控制块中的类型foo。在实际对象类型shared_ptr已知时,派生控制块在Y的构造函数中构造。但从那时起,shared_ptr只能通过control_block_base*与控制块进行通信。因此,破坏就是通过虚函数调用发生的。

C ++ 11中来自右值shared_ptr<void>的{​​{1}}的“移动构造”只需要复制两个内部指针,而不必操纵引用计数。这是因为无论如何,右值shared_ptr<foo>即将消失:

shared_ptr<foo>

最明显的是// shared_ptr<foo> constructed and destructed within this statement std::shared_ptr<void> p = std::make_shared<foo>(); 构造函数源代码:

shared_ptr

在转换构造之前,引用计数仅为1.在转换构造之后,引用计数仍为1,源在其析构函数运行之前指向任何内容。简而言之,这就是移动语义的乐趣! : - )