当前位置: 首页 > 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;听说也收到了不少众筹…...

手游刚开服就被攻击怎么办?如何防御DDoS?

开服初期是手游最脆弱的阶段&#xff0c;极易成为DDoS攻击的目标。一旦遭遇攻击&#xff0c;可能导致服务器瘫痪、玩家流失&#xff0c;甚至造成巨大经济损失。本文为开发者提供一套简洁有效的应急与防御方案&#xff0c;帮助快速应对并构建长期防护体系。 一、遭遇攻击的紧急应…...

【解密LSTM、GRU如何解决传统RNN梯度消失问题】

解密LSTM与GRU&#xff1a;如何让RNN变得更聪明&#xff1f; 在深度学习的世界里&#xff0c;循环神经网络&#xff08;RNN&#xff09;以其卓越的序列数据处理能力广泛应用于自然语言处理、时间序列预测等领域。然而&#xff0c;传统RNN存在的一个严重问题——梯度消失&#…...

【HTML-16】深入理解HTML中的块元素与行内元素

HTML元素根据其显示特性可以分为两大类&#xff1a;块元素(Block-level Elements)和行内元素(Inline Elements)。理解这两者的区别对于构建良好的网页布局至关重要。本文将全面解析这两种元素的特性、区别以及实际应用场景。 1. 块元素(Block-level Elements) 1.1 基本特性 …...

深入解析C++中的extern关键字:跨文件共享变量与函数的终极指南

&#x1f680; C extern 关键字深度解析&#xff1a;跨文件编程的终极指南 &#x1f4c5; 更新时间&#xff1a;2025年6月5日 &#x1f3f7;️ 标签&#xff1a;C | extern关键字 | 多文件编程 | 链接与声明 | 现代C 文章目录 前言&#x1f525;一、extern 是什么&#xff1f;&…...

【JavaWeb】Docker项目部署

引言 之前学习了Linux操作系统的常见命令&#xff0c;在Linux上安装软件&#xff0c;以及如何在Linux上部署一个单体项目&#xff0c;大多数同学都会有相同的感受&#xff0c;那就是麻烦。 核心体现在三点&#xff1a; 命令太多了&#xff0c;记不住 软件安装包名字复杂&…...

MySQL用户和授权

开放MySQL白名单 可以通过iptables-save命令确认对应客户端ip是否可以访问MySQL服务&#xff1a; test: # iptables-save | grep 3306 -A mp_srv_whitelist -s 172.16.14.102/32 -p tcp -m tcp --dport 3306 -j ACCEPT -A mp_srv_whitelist -s 172.16.4.16/32 -p tcp -m tcp -…...

Java毕业设计:WML信息查询与后端信息发布系统开发

JAVAWML信息查询与后端信息发布系统实现 一、系统概述 本系统基于Java和WML(无线标记语言)技术开发&#xff0c;实现了移动设备上的信息查询与后端信息发布功能。系统采用B/S架构&#xff0c;服务器端使用Java Servlet处理请求&#xff0c;数据库采用MySQL存储信息&#xff0…...

GitFlow 工作模式(详解)

今天再学项目的过程中遇到使用gitflow模式管理代码&#xff0c;因此进行学习并且发布关于gitflow的一些思考 Git与GitFlow模式 我们在写代码的时候通常会进行网上保存&#xff0c;无论是github还是gittee&#xff0c;都是一种基于git去保存代码的形式&#xff0c;这样保存代码…...

LOOI机器人的技术实现解析:从手势识别到边缘检测

LOOI机器人作为一款创新的AI硬件产品&#xff0c;通过将智能手机转变为具有情感交互能力的桌面机器人&#xff0c;展示了前沿AI技术与传统硬件设计的完美结合。作为AI与玩具领域的专家&#xff0c;我将全面解析LOOI的技术实现架构&#xff0c;特别是其手势识别、物体识别和环境…...

在树莓派上添加音频输入设备的几种方法

在树莓派上添加音频输入设备可以通过以下步骤完成&#xff0c;具体方法取决于设备类型&#xff08;如USB麦克风、3.5mm接口麦克风或HDMI音频输入&#xff09;。以下是详细指南&#xff1a; 1. 连接音频输入设备 USB麦克风/声卡&#xff1a;直接插入树莓派的USB接口。3.5mm麦克…...