当前位置: 首页 > news >正文

C++ 学习系列 -- 智能指针 make_shared 与 make_unique

一   make_shared 

1.1  make_shared 是什么?

      c++ 11 中 引入了智能指针 shared_ptr,以及一个模板函数 make_shared 来生成一个制定类型的 shared_ptr。

1.2  引入 make_shared ,解决了什么问题?

   make_shared的引入,主要有两点的提升:性能 与 异常安全

C++11 make_shared - 简书 (jianshu.com)

  •   性能

        有如下两种方式生成  shared_ptr

int  main()
{// 1.shared_ptr<string> p1(new string("66888"));cout << *p1 << endl;// 2.shared_ptr<string> p2 = make_shared<string>("888888");cout << *p2 << endl;return 0;
}

              使用 make_shared 性能要更好一些

  shared_ptr<string> p1(new string("66888"));  会分配两次内存

每个std::shared_ptr都指向一个控制块,控制块包含被指向对象的引用计数以及其他东西。这个控制块的内存是在std::shared_ptr的构造函数中分配的。因此直接使用new,需要一块内存分配给string,还要一块内存分配给控制块。

  使用   shared_ptr<string> p2 = make_shared<string>("888888");  分配一次内存

  一次分配就足够了。这是因为std::make_shared申请一个单独的内存块来同时存放 string 对象和控制块。

  •   异常安全
// d.h
#include<iostream>class D
{
public:D(){std::cout << "constructor D " << std::endl;}~D(){std::cout << "destructor D " << std::endl;}};// main.cppint getVal()
{throw 888;return 66;
}void  init(shared_ptr<D> ptr, int val)
{}int main()
{// 1. init(std::shared_ptr<D>(new D), getVal());// 2.init(std::make_shared<D>(), getVal());return 0;
}

  第 1 种的调用方式分为三步:

  1.  new D

  2. 调用 shared_ptr 类的构造函数

  3. 调用 getVal 函数  

        针对不同的编译器,上述三步的执行顺序可能不同,若是 其中的第 2 步 与第 3 步发生了调换,那么在执行 getVal 抛出异常后,就不会再执行 第 2 步,没有调用 shared_ptr 的构造函数,那么就无法用 shared_ptr 来管理 第 1 步分配出的内存。

  第 2 种方式,用 make_shared 就不会出现该问题,其分为两步

   1. make_shared 生成 shared_ptr 指针

   2.调用  getVal 函数  

上面的 1 步 与 2 步,即便发生顺序调换,也不会出现内存无法管理的情况

1.3   make_shared 源码解析

  template<typename _Tp, typename... _Args>inline shared_ptr<_Tp>make_shared(_Args&&... __args){typedef typename std::remove_const<_Tp>::type _Tp_nc; // 去除 _Tp 的 const 特性,获取到其类本身return std::allocate_shared<_Tp>(std::allocator<_Tp_nc>(),std::forward<_Args>(__args)...);// std::allocator会给我们分配一块_Tp_nc实例需要的内存空间// 完美转发(perfect forward)剩余构造函数的参数}template<typename _Tp, typename _Alloc, typename... _Args>inline shared_ptr<_Tp>allocate_shared(const _Alloc& __a, _Args&&... __args){return shared_ptr<_Tp>(_Sp_make_shared_tag(), __a,std::forward<_Args>(__args)...); // 调用 shared_ptr 的 private 构造函数}​

make_shared 的参数是万能引用 && ,因此参数既可以接受左值也可以接受右值。

allocate_shared 是 shared_ptr 类的 friend 函数,因此可以调用 shared_ptr 的 private 构造函数。

总之,下面的 private 构造函数将实例内存与计数器模块的内存绑定在了一起。

template<typename _Alloc, typename... _Args>__shared_ptr(_Sp_alloc_shared_tag<_Alloc> __tag, _Args&&... __args)

详细解析见:从零开始写一个shared_ptr-make_shared源代码解析 - 知乎 (zhihu.com)

1.4  make_shared 使用例子

// person.h
class Person
{
public:Person(std::string name);Person(const Person& p);~Person();std::string& getName();void setName(std::string& name);private:std::string m_name;
};// person.cpp
#include "person.h"
#include<iostream>
Person::Person(std::string name):m_name(name)
{std::cout << "Person constructor name: " << m_name << std::endl;
}Person::Person(const Person& p)
{this->m_name = p.m_name;std::cout << "Person  copy constructor name: " << this->m_name << std::endl;
}Person::~Person()
{std::cout << "Person destructor name: " << m_name << std::endl;
}std::string& Person::getName()
{return m_name;
}void Person::setName(std::string& name)
{this->m_name = name;
}// main.cpp
void testSharedPtr2()
{// 1.shared_ptr<Person>  ptr(new Person("Tom"));cout << ptr->getName() << endl;// 2.shared_ptr<Person>  ptr2 = make_shared<Person>("Jerry");cout << ptr2->getName() << endl;}int main()
{testSharedPtr2();return 0;
}

二   make_unique 

2.1  make_unique 是什么?

        make_unique 是 c++14 加入标准库的,用于生成独占型指针 std::unique_ptr 

2.2  make_unique  解决了什么问题?

     用 make_unique 生成独占型指针代码量更少,符合现代 c++ 尽量避免使用 new  来构造的原则

2.3  make_unique  简单版实现

template<typename T, typename... Arg>  // 可能有多个参数,所以用 ...
unique_ptr<T>
my_make_unique(Arg&& ... s)  // 支持左值与右值,所以要用万能引用
{return unique_ptr<T>(new T(std::forward<Arg>(s)...));
}int main()
{unique_ptr<string> ptr = my_make_unique<string>("abcdd");cout << *ptr << endl;return 0;
}

2.4  make_unique  使用例子

很简单

int  main()
{std::unique_ptr<std::string> a = std::make_unique("6666");return 0;
}

参考:C++11 make_shared - 简书 (jianshu.com)

从零开始写一个shared_ptr-make_shared源代码解析 - 知乎 (zhihu.com)

​《Effective Modern C++》学习笔记之条款二十一:优先选用std::make_unique和std::make_shared,而非直接new - 知乎 (zhihu.com)

http://www.lryc.cn/news/151494.html

相关文章:

  • 贝叶斯神经网络 - 捕捉现实世界的不确定性
  • games101作业1
  • LeetCode 面试题 02.08. 环路检测
  • 【Linux】线程安全-生产者消费者模型
  • 优化(2) 2023/09/03
  • Swap and Reverse 题解
  • 单元测试:优雅编写Kotlin单元测试
  • 深度学习入门教学——卷积神经网络CNN
  • 【MySQL】MySQL系统变量(system variables)列表(mysqld --verbose --help的结果例)
  • Python学习之四 数据输入与输出
  • VBA技术资料MF51:VBA_在Excel中突出显示唯一值
  • Mqtt学习笔记--交叉编译移植(1)
  • Gateway的服务网关
  • 信息化发展18
  • TypeScript学习 + 贪吃蛇项目
  • YOLO-NAS详细教程-介绍如何进行物体检测
  • 容器没有命令时,如何查看进程、容器executable file not found in $PATH: unknown
  • 如何使用 Amazon EMR 在 Amazon EKS 上构建可靠、高效、用户友好的 Spark 平台
  • 国产IDE如何获得捐赠和风险投资
  • 【数学建模】清风数模正课5 相关性分析
  • Java设计模式:一、六大设计原则-03:里氏替换原则
  • jmeter 固定定时器
  • 【微服务部署】07-调用链追踪
  • 【C++入门】命名空间、缺省参数、函数重载、引用、内联函数
  • c++ 学习之 构造函数的使用规则
  • C++操作符重载的注意事项
  • 10 | Spark 查找每个单词的最大行号
  • CRE66365
  • React hook 10种常见 Hook
  • 图文详解PhPStudy安装教程