当前位置: 首页 > 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)

相关文章:

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

一 make_shared 1.1 make_shared 是什么&#xff1f; c 11 中 引入了智能指针 shared_ptr&#xff0c;以及一个模板函数 make_shared 来生成一个制定类型的 shared_ptr。 1.2 引入 make_shared &#xff0c;解决了什么问题&#xff1f; make_shared的引入&#xff0c;主…...

贝叶斯神经网络 - 捕捉现实世界的不确定性

贝叶斯神经网络 - 捕捉现实世界的不确定性 Bayesian Neural Networks 生活本质上是不确定性和概率性的&#xff0c;贝叶斯神经网络 (BNN) 旨在捕获和量化这种不确定性 在许多现实世界的应用中&#xff0c;仅仅做出预测是不够的&#xff1b;您还想知道您对该预测的信心有多大。例…...

games101作业1

题目 给定三维下三个点 v0(2.0, 0.0, −2.0), v1(0.0, 2.0, −2.0), v2(−2.0, 0.0, −2.0), 你需要将这三个点的坐标变换为屏幕坐标并在屏幕上绘制出对应的线框三角形 (在代码框架中&#xff0c;我们已经提供了 draw_triangle 函数&#xff0c;所以你只需要去构建变换矩阵即可…...

LeetCode 面试题 02.08. 环路检测

文章目录 一、题目二、C# 题解 一、题目 给定一个链表&#xff0c;如果它是有环链表&#xff0c;实现一个算法返回环路的开头节点。若环不存在&#xff0c;请返回 null。 如果链表中有某个节点&#xff0c;可以通过连续跟踪 next 指针再次到达&#xff0c;则链表中存在环。 为了…...

【Linux】线程安全-生产者消费者模型

文章目录 生产者消费者模型123规则应用场景优点忙闲不均生产者和消费者解耦支持高并发 代码模拟 生产者消费者模型 123规则 1个线程安全的队列&#xff1a;只要保证先进先出特性的数据结构都可以称为队列 这个队列要保证互斥&#xff08;就是保证当前只有一个线程对队列进行操…...

优化(2) 2023/09/03

今天重新温习了下clean abap&#xff0c;以前只是偶尔打开看几眼。今天把有些自己不熟悉的地方&#xff0c;重点研究了下。有几个点可以在以后工作使用。这几点可能并不能提升程序效率&#xff0c;但会大大提高代码可读性和代码的可扩展性&#xff1a; 用insert XXX into tabl…...

Swap and Reverse 题解

Swap and Reverse 题面翻译 题目描述 本题共有 t t t 组数据。 给定一个长度为 n n n 的字符串 s s s 和一个整数 k k k&#xff0c; s s s 只包含小写字母&#xff0c;你可以进行若干次操作&#xff08;可以是零次&#xff09;&#xff0c;具体操作如下&#xff1a; 选…...

单元测试:优雅编写Kotlin单元测试

一、MockK简介 MockK是一款功能强大、易于使用的Kotlin mocking框架。在编写单元测试时&#xff0c;MockK能够帮助我们简化代码、提高测试覆盖率&#xff0c;并改善测试的可维护性。除了基本用法外&#xff0c;MockK还提供了许多额外的功能和灵活的用法&#xff0c;让我们能够…...

深度学习入门教学——卷积神经网络CNN

目录 一、CNN简介 一、输入层 二、卷积层 三、池化层 四、全连接层 一、CNN简介 1、应用领域 检测任务 分类与检索 超分辨率重构 2、卷积网络与传统网咯的区别 传统神经网络和卷积神经网络都是用来提取特征的。神经网络&#xff1a; 可以将其看作是一个二维的。卷积神经…...

【MySQL】MySQL系统变量(system variables)列表(mysqld --verbose --help的结果例)

文章目录 【MySQL】MySQL系统变量&#xff08;system variables&#xff09;列表&#xff08;mysqld --verbose --help的结果例&#xff09;mysqld --verbose --help的结果例参考 【免责声明】文章仅供学习交流&#xff0c;观点代表个人&#xff0c;与任何公司无关。 编辑|SQL和…...

Python学习之四 数据输入与输出

(一) 脚本编程 前面的章节,组要学习了一些简单的Python编程,使用的是交互式解释器,本章节将开始进行脚本编程。可以使用多种编辑器或者IDE完成编码,主要使用vim。 参考前续小节的写法,我们给a、b分别赋值3和5。 在终端运行程序后发现,没有任何输出。这就是本次我们将要…...

VBA技术资料MF51:VBA_在Excel中突出显示唯一值

【分享成果&#xff0c;随喜正能量】世间万物&#xff0c;因果循环不休&#xff0c;你的善心善行&#xff0c;都可能成为你的善缘善果。每天忆佛念佛&#xff0c;每天都在佛菩萨的加持下生活&#xff0c;自然吉祥如意&#xff0c;法喜充满。 。 我给VBA的定义&#xff1a;VBA是…...

Mqtt学习笔记--交叉编译移植(1)

简述 Mqtt目前在物联网行业的应用比较多&#xff0c;mqtt属于应用层的一个中间件&#xff0c;这个中间件实现消息的订阅发布机制。网上介绍Mqtt的实现原来的比较多&#xff0c;这里不细介绍。 其实在我们之前的产品中&#xff0c;自己也开发的有类似的中间件&#xff0c;除了具…...

Gateway的服务网关

Gateway服务网关 Gateway网关是我们服务的守门神&#xff0c;所有微服务的统一入口。 网关的核心功能特性&#xff1a; 请求路由 权限控制 限流 架构如下&#xff1a; gateway使用 引入依赖 创建gateway服务&#xff0c;引入依赖 <!--网关--> <dependency>…...

信息化发展18

存储技术 1 、存储分类 2 、常用存储模式的技术与应用对比&#xff1a; ( 1 &#xff09; 存储虚拟化&#xff08; Storage Virtualization &#xff09; 是“ 云存储” 的核心技术之一。 它带给人们直接的好处是提高了存储利用率&#xff0c; 降低了存储成本&#xff0c; 简…...

TypeScript学习 + 贪吃蛇项目

TypeSCript简介 TypeScript是JavaScript的超集。它对JS进行了扩展&#xff0c;向JS中引入了类型的概念&#xff0c;并添加了许多新的特性。TS代码需要通过编译器编译为JS&#xff0c;然后再交由JS解析器执行。TS完全兼容JS&#xff0c;换言之&#xff0c;任何的JS代码都可以直…...

YOLO-NAS详细教程-介绍如何进行物体检测

对象检测是计算机视觉中的一项核心任务,可以检测和分类图像中的边界框。自从深度学习首次取得突破以来,它就以极快的速度获得普及和普及,并推动了医疗领域、监控、智能购物等众多公司的发展。考虑到它最终满足了两个基本需求,这一点也就不足为奇了端到端方式:找到所有当前…...

容器没有命令时,如何查看进程、容器executable file not found in $PATH: unknown

前言 当容器没有ps -ef命令时&#xff0c;可以通过以下的命令来查看容器的进程。 docker container top查看容器运行的进程&#xff08;该命令很有用&#xff09; #docker container top 命令用于查看容器运行的进程 #当容器里面没有ps -ef命令时&#xff0c;使用docker con…...

如何使用 Amazon EMR 在 Amazon EKS 上构建可靠、高效、用户友好的 Spark 平台

这是 SafeGraph 技术主管经理 Nan Zhu 与亚马逊云科技高级解决方案架构师 Dave Thibault 共同撰写的特约文章。 SafeGraph 是一家地理空间数据公司&#xff0c;管理着全球超过 4100 万个兴趣点&#xff08;POI&#xff0c;Point of Interest&#xff09;&#xff0c;提供品牌隶…...

国产IDE如何获得捐赠和风险投资

有人在开发VB6 脚本工具&#xff0c;有人在开发VB6的插件&#xff0c;把VB6变成VSCODE界面模式&#xff0c;再加上NUGET&#xff0c;NPM等包管理器原理的在线组件、源码下载功能。 还有TWINBASIC几乎80%代替了VB6&#xff0c;radbasic一直封闭&#xff0c;听说也收到了不少众筹…...

基于算法竞赛的c++编程(28)结构体的进阶应用

结构体的嵌套与复杂数据组织 在C中&#xff0c;结构体可以嵌套使用&#xff0c;形成更复杂的数据结构。例如&#xff0c;可以通过嵌套结构体描述多层级数据关系&#xff1a; struct Address {string city;string street;int zipCode; };struct Employee {string name;int id;…...

shell脚本--常见案例

1、自动备份文件或目录 2、批量重命名文件 3、查找并删除指定名称的文件&#xff1a; 4、批量删除文件 5、查找并替换文件内容 6、批量创建文件 7、创建文件夹并移动文件 8、在文件夹中查找文件...

Admin.Net中的消息通信SignalR解释

定义集线器接口 IOnlineUserHub public interface IOnlineUserHub {/// 在线用户列表Task OnlineUserList(OnlineUserList context);/// 强制下线Task ForceOffline(object context);/// 发布站内消息Task PublicNotice(SysNotice context);/// 接收消息Task ReceiveMessage(…...

鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个生活电费的缴纳和查询小程序

一、项目初始化与配置 1. 创建项目 ohpm init harmony/utility-payment-app 2. 配置权限 // module.json5 {"requestPermissions": [{"name": "ohos.permission.INTERNET"},{"name": "ohos.permission.GET_NETWORK_INFO"…...

EtherNet/IP转DeviceNet协议网关详解

一&#xff0c;设备主要功能 疆鸿智能JH-DVN-EIP本产品是自主研发的一款EtherNet/IP从站功能的通讯网关。该产品主要功能是连接DeviceNet总线和EtherNet/IP网络&#xff0c;本网关连接到EtherNet/IP总线中做为从站使用&#xff0c;连接到DeviceNet总线中做为从站使用。 在自动…...

零基础设计模式——行为型模式 - 责任链模式

第四部分&#xff1a;行为型模式 - 责任链模式 (Chain of Responsibility Pattern) 欢迎来到行为型模式的学习&#xff01;行为型模式关注对象之间的职责分配、算法封装和对象间的交互。我们将学习的第一个行为型模式是责任链模式。 核心思想&#xff1a;使多个对象都有机会处…...

uniapp中使用aixos 报错

问题&#xff1a; 在uniapp中使用aixos&#xff0c;运行后报如下错误&#xff1a; AxiosError: There is no suitable adapter to dispatch the request since : - adapter xhr is not supported by the environment - adapter http is not available in the build 解决方案&…...

【C++从零实现Json-Rpc框架】第六弹 —— 服务端模块划分

一、项目背景回顾 前五弹完成了Json-Rpc协议解析、请求处理、客户端调用等基础模块搭建。 本弹重点聚焦于服务端的模块划分与架构设计&#xff0c;提升代码结构的可维护性与扩展性。 二、服务端模块设计目标 高内聚低耦合&#xff1a;各模块职责清晰&#xff0c;便于独立开发…...

DeepSeek 技术赋能无人农场协同作业:用 AI 重构农田管理 “神经网”

目录 一、引言二、DeepSeek 技术大揭秘2.1 核心架构解析2.2 关键技术剖析 三、智能农业无人农场协同作业现状3.1 发展现状概述3.2 协同作业模式介绍 四、DeepSeek 的 “农场奇妙游”4.1 数据处理与分析4.2 作物生长监测与预测4.3 病虫害防治4.4 农机协同作业调度 五、实际案例大…...

Python ROS2【机器人中间件框架】 简介

销量过万TEEIS德国护膝夏天用薄款 优惠券冠生园 百花蜂蜜428g 挤压瓶纯蜂蜜巨奇严选 鞋子除臭剂360ml 多芬身体磨砂膏280g健70%-75%酒精消毒棉片湿巾1418cm 80片/袋3袋大包清洁食品用消毒 优惠券AIMORNY52朵红玫瑰永生香皂花同城配送非鲜花七夕情人节生日礼物送女友 热卖妙洁棉…...