ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

c-cpp make_shared用于无效指针

2019-10-09 12:19:32  阅读:341  来源: 互联网

标签:c c11 smart-pointers


我想使用std :: make_shared创建一个空指针.由于make_shared应该比shared_ptr(new T)快,并且可以保存异常,所以我想知道是否有一个库函数以make_shared的方式创建shared_ptr(new foo).

解决方法:

您可以转换任何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 *,其中T与shared_ptr< T>中的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 *.而已. (除了增加/减少参考计数以外,还考虑了临时副本的复制和销毁-可以通过构造从右值中消除它).当引用计数变为零时,仍然是控制块会破坏通过p1找到的foo. p2不参与销毁操作.

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

shared_ptr< void>的“移动构造”是指将其作为对象.来自右值shared_ptr< foo> C 11中的C语言只需要复制两个内部指针,而不必操纵引用计数.这是因为右值shared_ptr< foo>无论如何都会消失:

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

在shared_ptr构造函数源代码中可以最清楚地看出这一点:

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,而在其析构函数运行之前,源不指向任何内容.简而言之,这就是移动语义的乐趣!

标签:c,c11,smart-pointers
来源: https://codeday.me/bug/20191009/1879124.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有