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.mzph.cn/news/64793.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【计算机硬件CPU】

【计算机硬件CPU】 1、计算机硬件的五大单元2、一切设计的起点&#xff1a; CPU 的架构3、精简指令集 &#xff08;Reduced Instruction Set Computer, RISC&#xff09;4、复杂指令集&#xff08;Complex Instruction Set Computer, CISC&#xff09;5、例题&#xff1a;最新的…

Vue框架--Vue中el和data的两种写法

data与el的2种写法 1.el有2种写法 (1).new Vue时候配置el属性。 (2).先创建Vue实例&#xff0c;随后再通过vm.$mount(#root)指定el的值。 2.data有2种写法 (1).对象式 (2).函数式 如何选择&#xff1a;目前哪种写法都可以&#xff0c;以后学习到组件时&#xff…

Selenium基础 — CSS选择器定位大全

1、css属性定位 css选择器策略示例说明#id#telA选择id"telA"的所有元素。.class.telA选择 class"telA”的所有元素。[属性名属性值][nametelA]除了id和class属性&#xff0c;其他属性的定位格式[attribute][target]选择带有target 属性所有元素。**选择所有元素…

一些测试知识

希望能起到帮助&#xff0c;博主主页&#xff1a; https://blog.csdn.net/qq_57785602/category_12023254.html?spm1001.2014.3001.5482 软件测试理论 测试的依据&#xff1a; 需求&#xff0c;规格说明&#xff0c;模型&#xff0c;用户需求等 什么是软件测试 描述一种来…

Python Opencv实践 - 矩形轮廓绘制(直边矩形,最小外接矩形)

import cv2 as cv import numpy as np import matplotlib.pyplot as pltimg cv.imread("../SampleImages/stars.png") plt.imshow(img[:,:,::-1])img_gray cv.cvtColor(img, cv.COLOR_BGR2GRAY) #通过cv.threshold转换为二值图 ret,thresh cv.threshold(img_gray,…

手写Mybatis:第5章-数据源的解析、创建和使用

文章目录 一、目标&#xff1a;数据源的解析、创建和使用二、设计&#xff1a;数据源的解析、创建和使用三、实现&#xff1a;数据源的解析、创建和使用3.1 引入依赖3.2 工程结构3.3 数据源解析、创建和使用关系图3.4 事务管理接口和事务工厂3.4.1 事务的隔离级别3.4.2 定义事务…

ChatGPT⼊门到精通(3):ChatGPT 原理

OpenAI在2022年11⽉份发布ChatGPT&#xff0c;强⼤的⽂字对话、创意写作能⼒&#xff0c;全球掀起了⼀ 波AI浪潮。本⽂对ChatGPT的技术原理、厉害之处、可能的落地⽅向等⽅⾯进⾏了全⾯ 的解析&#xff0c;看完后会对ChatGPT有更深⼊的了解。 ⼀、前⾔ 2022年11⽉30⽇&#x…

libdrm全解析四十 —— 源码全解析(37)

接前一篇文章&#xff1a;libdrm全解析三十九 —— 源码全解析&#xff08;36&#xff09; 本文参考以下博文&#xff1a; DRM 驱动程序开发&#xff08;VKMS&#xff09; 特此致谢&#xff01; 前一篇文章讲解完了资源的释放流程中的munmap()和drmIoctl(DRM_IOCTL_MODE_DEST…

配置环境变量的作用

配置环境变量的作用 一般运行过程&#xff1a;寻找QQ.exe所在的目录&#xff0c;输入QQ.exe配置环境变量&#xff1a;把QQ所在的路径配给操作系统Path&#xff0c; 在任何路径下都能运行QQ.exe 举例&#xff1a; 定义变量&#xff1a;SCALA_HOME SCALA_HOME、JAVA_HOME 等这…

【论文精读】Learning Transferable Visual Models From Natural Language Supervision

Learning Transferable Visual Models From Natural Language Supervision 前言Abstract1. Introduction and Motivating Work2. Approach2.1. Creating a Sufficiently Large Dataset2.2. Selecting an Efficient Pre-Training Method2.3. Choosing and Scaling a Model2.4. P…

基于STM32的ADC采样及各式滤波实现(HAL库,含VOFA+教程)

前言&#xff1a;本文为手把手教学ADC采样及各式滤波算法的教程&#xff0c;本教程的MCU采用STM32F103ZET6。以HAL库的ADC采样函数为基础进行教学&#xff0c;通过各式常见滤波的实验结果进行分析对比&#xff0c;搭配VOFA工具直观的展示滤波效果。ADC与滤波算法都是嵌入式较为…

第十六章 ObjectScript - 日期和时间值

文章目录 第十六章 ObjectScript - 日期和时间值日期和时间值当地时间UTC Time日期和时间转换$H 格式的详细信息 第十六章 ObjectScript - 日期和时间值 日期和时间值 当地时间 要访问当前进程的日期和时间&#xff0c;可以使用 $HOROLOG 特殊变量。因此&#xff0c;在许多 …

【FreeRTOS】信号量的相关函数使用及示例解释

FreeRTOS中的信号量是一种用于任务间同步的机制。它可以用来实现任务之间的互斥访问共享资源或者等待某个事件发生。 文章目录 信号量类型1. 二进制信号量&#xff08;Binary Semaphore&#xff09;&#xff1a;2. 计数信号量&#xff08;Counting Semaphore&#xff09;&…

python in excel 如何尝鲜 有手就行

众所周知&#xff0c;微软在8月下旬放出消息python已入驻excel&#xff0c;可到底怎么实现呢。 今天我就将发布python in excel的保姆级教程&#xff0c;开始吧&#xff01; 获取office 365 账号 首先我们要有微软office365 这时候需要再万能的某宝去找一个账号&#xff0c;…

Android JNI系列详解之ndk-build工具的使用

一、Android项目中使用ndk-build工具编译库文件 之前介绍过CMake编译工具的使用&#xff0c;今天介绍一种ndk自带的编译工具ndk-build的使用。 ndk-build目前主要有两种配置使用方式&#xff1a; 如上图所示&#xff0c;第一种方式是Android.mkApplication.mkgradle的方式生成…

5.Redis-string

string 字符串 字符串类型是 Redis 最基础的数据类型&#xff0c;关于字符串需要特别注意&#xff1a; 1.⾸先Redis中所有 key 的类型都是字符串类型&#xff0c;⽽且其他⼏种数据结构也都是在字符串类似基础上构建的&#xff0c;例如 list 和 set 的元素类型是字符串类型。 2…

Web_单一视频文件mp4转换为m3u分段ts文件实现边下边播

一、下载ffmpeg: Builds - CODEX FFMPEG @ gyan.dev 二、转换视频文件: 先解压缩,会看到如下结构: 进入bin目录,把需要转换的视频文件复制过来,同时新建一个文件夹用来存放转换后的文件,然后按住Shift键同时单击鼠标右键,选择打开Powershell窗口: 输入以下命令(根据…

【管理运筹学】第 7 章 | 图与网络分析(1,图论背景以及基本概念、术语)

文章目录 引言一、图与网络的基本知识1.1 图与网络的基本概念1.1.1 图的定义1.1.2 图中相关术语1.1.3 一些特殊图类1.1.4 图的运算 写在最后 引言 按照正常进度应该学习动态规划了&#xff0c;但我想换换口味&#xff0c;而且动态规划听说也有一定难度&#xff0c;还不一定会考…

UE5- c++ websocket客户端写法

# 实现目标 ue5 c 实现socket客户端&#xff0c;读取服务端数据&#xff0c;并进行解析 #实现步骤 {projectName}.Build.cs里增加 "WebSockets","JsonUtilities", "Json"配置信息&#xff0c;最终输出如下&#xff1a; using UnrealBuildTool;…

IDEA 快捷键

方法参数顺序快速调整 参数顺序调整 交换参数位置 参数交换位置 编码过程中经常碰到函数调用的参数顺序需要调整的情况。 比如单元测试中&#xff0c;期望和实际值得参数顺序反了&#xff0c;就可以选中参数后或者光标放到要调整的参数位置&#xff0c;然后用 CTRL SHIFTA…