cpp make_shared用于void指针 [英] cpp make_shared for void pointers

查看:327
本文介绍了cpp make_shared用于void指针的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想使用std :: make_shared创建一个void指针。因为make_shared应该比shared_ptr(new T)更快,并且异常save我不知道是否有一个库函数在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.

推荐答案

您可以将任何 shared_ptr< foo> 转换为 shared_ptr< void> 没有与 make_shared 相关的效率损失:

You can convert any shared_ptr<foo> to shared_ptr<void> without the loss of efficiency associated with make_shared:

#include <memory>

struct foo {};

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

转换会保留 foo void * 引用它。

The conversion keeps the foo and the reference count in the same memory allocation, even though you now refer to it via a void*.

更新

这如何工作?

std :: shared_ptr< foo> 是两个指针:

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

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

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 the shared_ptr<T> constructor saw, say Y (which may or may not be the same as a T).

p2 有类型 T * 其中 T 是相同的 T ,如 shared_ptr< T> 。认为这是存储对象的静态类型。当取消引用 shared_ptr< T> 时,被取消引用的是 p2 。当你销毁一个 shared_ptr< T> ,如果引用计数变为零,它是控制块中的指针,帮助破坏 foo

p2 has type T* where the T is the same T as in shared_ptr<T>. Think of this as the "static" type of the stored object. When you dereference a shared_ptr<T>, it is p2 that gets dereferenced. When you destruct a shared_ptr<T>, and if the reference count goes to zero, it is the pointer in the control block that aids in the destruction of foo.

在上图中,控制块和 foo 动态分配。 p1 是拥有指针,控制块中的指针是拥有指针。 p2 是非拥有指针。 p2 函数取消引用(箭头运算符 get()等)。 )。

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.).

当您使用 make_shared< foo>()时,实现有机会将 foo 在控制块中,旁边的引用计数和其他数据:

When you use make_shared<foo>(), the implementation has the opportunity to put the foo right in the control block, alongside of the reference counts and other data:

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

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

The optimization here is that there is now only a single allocation: the control block which now embeds the foo.

当上述操作被转换为 shared_ptr< void> 时,所有这一切都是:

When the above gets converted to a shared_ptr<void>, all that happens is:

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

p2 的类型从 foo * 更改为 void * 。而已。 (除了递增/递减引用计数以考虑临时的副本和破坏 - 这可以通过从右值建构而被省略)。当引用计数变为零时,仍然是控制块破坏通过 p1 找到的 foo p2 不参与销毁操作。

I.e. The type of p2 changes from foo* to void*. 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 the foo, found via p1. p2 does not participate in the destruction operation.

p1 实际上指向控制块的通用基类。这个基类不知道存储在派生控制块中的 foo 类型。在实际对象类型 Y 已知时,派生控制块在 shared_ptr 的构造函数中构造。但从那时起, shared_ptr 只能通过 control_block_base * 与控制块通信。

p1 actually points to a generic base class of the control block. This base class is ignorant of the type foo stored in the derived control block. The derived control block is constructed in shared_ptr's constructor at the time the actual object type Y is known. But from then on the shared_ptr can only communicate with the control block via a control_block_base*. So things like destruction happen via a virtual function call.

shared_ptr< void> 的移动构造从C ++ 11中的右值 shared_ptr< foo> 只需要复制两个内部指针,而不必操作引用计数。这是因为右值 shared_ptr< foo> 即将消失:

The "move construction" of a shared_ptr<void> from an rvalue shared_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 rvalue shared_ptr<foo> is about to go away anyway:

// shared_ptr<foo> constructed and destructed within this statement
std::shared_ptr<void> p = std::make_shared<foo>();

这可以在 shared_ptr constructor source code:

This can be seen most plainly in the shared_ptr constructor source code:

template<class _Tp>
template<class _Yp>
inline _LIBCPP_INLINE_VISIBILITY
shared_ptr<_Tp>::shared_ptr(shared_ptr<_Yp>&& __r,
                            typename enable_if<is_convertible<_Yp*, _Tp*>::value, __nat>::type)
         _NOEXCEPT
    : __ptr_(__r.__ptr_),
      __cntrl_(__r.__cntrl_)
{
    __r.__ptr_ = 0;
    __r.__cntrl_ = 0;
}

在转换构造之前,引用计数只有1。引用计数仍然是1,源指向没有任何就在它的析构函数运行之前。简而言之,这是移动语义的快乐! : - )

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! :-)

这篇关于cpp make_shared用于void指针的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆