条款18:对独占资源使用std::unique_ptr

一、默认情况下 unique_ptr 大小等同于原始指针

unique_ptr 不允许拷贝,只允许移动。(移动之后,源指针被设置为nullptr)

std::unique_ptr<Test> uptr = std::unique_ptr<Test>(new Test(10));
auto size = sizeof(uptr);
std::unique_ptr<Test> uptr1 = std::move(uptr);
std::shared_ptr<Test> sptr2 = std::move(uptr1);

二、unique_ptr 作为继承乘次结构中对象的两个函数返回类型

  • 为什么要用智能指针?
    • 因为多态的需求,例如工厂模式
  • 为什么要用智能指针?
    • 栈上内容传不出来,堆上内存不好控制

三、智能指针的自定义删除器

// 方式1
auto delInvmt1=[](Investment* pInvestment){ std::cout << "delete" << std::endl;delete pInvestment;}
// 方式2
void delInvmt2(Investment* pInvestment)
{ std::cout << "delete" << std::endl;delete pInvestment;
}// 调用
std::unique_ptr<Investment, void(*)(Investment*)> uptr2(nullptr, delInvmt2); // 16字节
std::unique_ptr<Investment, decltype(delInvmt1)> uptr1(nullptr, delInvmt1);  // 8字节
  • 尽可能的传入lambda表达式,而不是指针
  • 具有很多状态的自定义删除器会产生大尺寸的std::unique_ptr对象。如果你发现自定义删除器使得你的std::unique_ptr 变得过大,则你需要审视修改你的设计

例子

#include <memory>
#include <iostream>class Investment
{
public:virtual ~Investment() {}
};class Stock : public Investment
{
public:Stock(int a) { std::cout << "Stock(int a)" << std::endl; }~Stock() override { std::cout << "~Stock()" << std::endl; }
};
class Bond : public Investment
{
public:Bond(int a, int b) { std::cout << "Bond(int a, int b)" << std::endl; }~Bond() override { std::cout << "~Bond()" << std::endl; }
};
class RealEstate : public Investment
{
public:RealEstate(int a, int b, int c) { std::cout << "RealEstate(int a, int b, int c)" << std::endl; }~RealEstate() override { std::cout << "~RealEstate()" << std::endl; }
};// 方式1
template <typename... Ts>
Investment *makeInvestment_test(Ts &&...params)
{Investment *ptr;constexpr int numArgs = sizeof...(params);if constexpr (numArgs == 1){Stock stock(std::forward<Ts>(params)...);ptr = &stock;  //传不出去}if constexpr (numArgs == 2){Bond bond(std::forward<Ts>(params)...);ptr = &bond;}if constexpr (numArgs == 3){RealEstate realEstate(std::forward<Ts>(params)...);ptr = &realEstate;}return ptr;
}// 方式2
template <typename... Ts>
Investment *makeInvestment_test2(Ts &&...params)
{Investment *ptr;constexpr int numArgs = sizeof...(params);if constexpr (numArgs == 1){Stock *stock = new Stock(std::forward<Ts>(params)...);ptr = stock;}if constexpr (numArgs == 2){Bond *bond = new Bond(std::forward<Ts>(params)...);ptr = bond;}if constexpr (numArgs == 3){RealEstate *realEstate = new RealEstate(std::forward<Ts>(params)...);ptr = &realEstate;}return ptr;
}// 方式3
template <typename... Ts>   // 返回指向对象的std::unique_ptr,
std::unique_ptr<Investment> // 对象使用给定实参创建
makeInvestment(Ts &&...params)
{std::unique_ptr<Investment> uptr{nullptr};constexpr int numArgs = sizeof...(params);if constexpr (numArgs == 1){uptr.reset(new Stock(std::forward<Ts>(params)...));}if constexpr (numArgs == 2){uptr.reset(new Bond(std::forward<Ts>(params)...));}if constexpr (numArgs == 3){uptr.reset(new RealEstate(std::forward<Ts>(params)...));}return uptr;
}auto delInvmt = [](Investment *pInvestment) // 自定义删除器
{                                           // (lambda表达式)std::cout << "delete" << std::endl;delete pInvestment;
};// 方式4
template <typename... Ts>
std::unique_ptr<Investment, decltype(delInvmt)> // 更改后的返回类型
makeInvestment2(Ts &&...params)
{std::unique_ptr<Investment, decltype(delInvmt)> // 应返回的指针uptr(nullptr, delInvmt);constexpr int numArgs = sizeof...(params);if constexpr (numArgs == 1){uptr.reset(new Stock(std::forward<Ts>(params)...));}if constexpr (numArgs == 2){uptr.reset(new Bond(std::forward<Ts>(params)...));}if constexpr (numArgs == 3){uptr.reset(new RealEstate(std::forward<Ts>(params)...));}return uptr;
}// 方式5
template <typename... Ts>
auto makeInvestment3(Ts &&...params) // C++14
{auto delInvmt2 = [](Investment *pInvestment) // 现在在{                                            // makeInvestment里std::cout << "delete" << std::endl;delete pInvestment;};std::unique_ptr<Investment, decltype(delInvmt2)> // 应返回的指针uptr(nullptr, delInvmt2);constexpr int numArgs = sizeof...(params);if constexpr (numArgs == 1){uptr.reset(new Stock(std::forward<Ts>(params)...));}if constexpr (numArgs == 2){uptr.reset(new Bond(std::forward<Ts>(params)...));}if constexpr (numArgs == 3){uptr.reset(new RealEstate(std::forward<Ts>(params)...));}return uptr;
}void delInvmt3(Investment *pInvestment) // 函数形式的
{                                       // 自定义删除器std::cout << "delete" << std::endl;delete pInvestment;
}int main()
{{Investment *ptr = makeInvestment_test(1);Investment *ptr2 = makeInvestment_test2(1);std::cout << "over";}{std::unique_ptr<Investment> uptrS = makeInvestment(1);//     auto size = sizeof(uptrS);//     std::unique_ptr<Investment> uptrB = makeInvestment(1, 2);//     std::unique_ptr<Investment> uptrR = makeInvestment(1, 2, 3);}{auto uptrS = makeInvestment2(1);//     auto size = sizeof(uptrS);//     std::unique_ptr<Investment, decltype(delInvmt)> uptrB = makeInvestment2(1, 2);//     std::unique_ptr<Investment, decltype(delInvmt)> uptrR = makeInvestment2(1, 2, 3);}// {//     auto uptrS = makeInvestment3(1);//     auto size = sizeof(uptrS);//     auto uptrB = makeInvestment3(1, 2);//     auto uptrR = makeInvestment3(1, 2, 3);// }// {//     std::unique_ptr<Investment, void (*)(Investment *)> uptr(nullptr, delInvmt3);//     std::unique_ptr<Investment, decltype(delInvmt)> uptr2(nullptr, delInvmt);//     auto size = sizeof(uptr);//     size = sizeof(uptr2);//     std::cout << "over";// }std::cout << "over" << std::endl;return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/891025.shtml

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

相关文章

vue2 升级为 vite 打包

VUE2 中使用 Webpack 打包、开发&#xff0c;每次打包时间太久&#xff0c;尤其是在开发的过程中&#xff0c;本文记录一下 VUE2 升级Vite 步骤。 安装 Vue2 Vite 依赖 dev 依赖 vitejs/plugin-vue2": "^2.3.3 vitejs/plugin-vue2-jsx": "^1.1.1 vite&…

20241227在ubuntu20.04.6系统中,如何用watch命令每秒钟调用nvidia-smi来监控GPU

watch -n 1 nvidia-smi 20241227在ubuntu20.04.6系统中&#xff0c;如何用watch命令每秒钟调用nvidia-smi来监控GPU 2024/12/27 17:04 缘起&#xff1a;在ubuntu20.04.6系统中&#xff0c;使用M6000显卡来跑whisper&#xff0c;显存拉满/占用巨大&#xff0c;但是CPU占用比低&…

[江科大STM32] 第五集STM32工程模板——笔记

保存&#xff0c;进去选芯片型号&#xff0c;我们是F10C8T6 再添加一些文件&#xff0c;自己看路径 然后去 复习这三文件 打开KEIL add existing那个&#xff0c;添加已经存在的文件 还有5个.c.h文件也要添加进来 回到KEIL 点击旁边的settings 如果你用寄存器开发就建到这里就可…

Bitmap(BMP)图像信息分析主要说明带压缩的形式

文章目录 参考资料Bitmap图片结构Bitmap图片组成实例说明 参考资料 微软官方-位图存储 Bitmap图片结构 序号名称说明1Bitmap File HeaderBitmap文件头2Bitmap Info HeaderBitmap信息头3Color Palette Data调色板数据4Bitmap Image Data图像数据 说明 Bitmap文件头的大小为…

二分和离散化

为什么把二分和离散化放一起&#xff1a;因为离散化其实是一种二分整数的过程。 二分 相信大家都接触过二分查找&#xff08;折半查找&#xff09;&#xff0c;这就是二分的思想。 二分通过每次舍弃一半并不存在答案的区间&#xff0c;进而快速锁定要求的答案&#xff08;二…

ESP-IDF学习记录(2)ESP-IDF 扩展的简单使用

傻瓜式记录一个示例的打开&#xff0c;编译&#xff0c;运行。后面我再一个个运行简单分析每个demo的内容。 1.打开示例代码 2.选择项目&#xff0c;文件夹 3.选择串口 4.选择调试方式 5.根据硬件GPIO口配置menuconfig 6.构建项目 7.烧录设备&#xff0c;选择串口UART方式 运行…

SpringMVC学习(一)——请求与响应处理

目录 一、SpringMVC简介 二、RequestMapping&#xff1a;请求路径映射 三、RestController 四、请求限定 五、请求处理 1.使用普通变量&#xff0c;收集请求参数 2.使用RequestParam明确指定获取参数 3.目标方法参数是一个pojo 4.RequestHeader&#xff1a;获取请求…

数据分析的分类和EDIT思维框架

为了服务于企业不同层次的决策&#xff0c;商业数据分析过程需要提供相应的数据科学产出物。 一般而言&#xff0c;数据分析需要经历从需求层、数据层、分析层到输出层四个阶段。 第一个阶段是需求层——确定目标&#xff0c;具体目标需要依据具体的层次进行分析&#xff1a…

实验五 时序逻辑电路部件实验

一、实验目的 熟悉常用的时序逻辑电路功能部件&#xff0c;掌握计数器、了解寄存器的功能。 二、实验所用器件和仪表 1、双 D触发器 74LS74 2片 2、74LS162 1片 3、74194 1片 4、LH-D4实验仪 1台 1.双…

iOS 中的 nil、Nil、NULL、NSNull 僵尸对象和野指针

iOS 中的 nil、Nil、NULL、NSNull 僵尸对象和野指针-CSDN博客 类型含义使用场景示例nil表示一个指向 Objective - C 对象的空指针。在 Objective - C 和 Swift&#xff08;与 Objective - C 交互时&#xff09;中用于表示对象不存在。当一个对象变量没有指向任何有效的对象实例…

JS面试题|[2024-12-28]

1.JS的设计原理是什么&#xff1f; JS引擎 运行上下文 调用栈 事件循环 回调 执行流程&#xff1a; JS引擎将代码解析为电脑可以执行的代码&#xff0c;调用一些API&#xff08;运行上下文&#xff09;让浏览器执行 JS是单线程的&#xff0c;每次从调用栈里面取出来的代码进行调…

全面了解 SQL Server:功能、优势与最佳实践

SQL Server 是微软公司推出的一款关系型数据库管理系统&#xff08;RDBMS&#xff09;&#xff0c;广泛应用于企业级数据存储、数据分析、应用开发等领域。作为全球最受欢迎的数据库管理系统之一&#xff0c;SQL Server 提供了强大的功能和工具&#xff0c;支持从小型应用到大型…

jdk动态代理和cglib动态代理对比

jdk动态代理和cglib动态代理对比&#xff1a; CGLIB 和 JDK 动态代理都可以用来在运行时生成代理对象 1. 基本概念 JDK 动态代理&#xff1a;只代理接口&#xff08;interface&#xff09;&#xff0c;无法代理类。它使用 java.lang.reflect.Proxy 类和 java.lang.reflect.I…

攻破 Kioptix Level 1 靶机

找教程然后自己练习&#xff0c;论菜狗的自我修养 基本步骤 1.确定目标IP 2.扫描端口&#xff0c;服务&#xff0c;版本信息&#xff0c;漏洞信息 3.查找漏洞可利用脚本 4.运行脚步 一、信息获取 arp-scan -l nmap -sS -p- -sV -sC -A --min-rate5000 192.168.5.130 二、查…

b站ip属地评论和主页不一样怎么回事

在浏览B站时&#xff0c;细心的用户可能会发现一个有趣的现象&#xff1a;某些用户的评论IP属地与主页显示的IP属地并不一致。这种差异引发了用户的好奇和猜测&#xff0c;究竟是什么原因导致了这种情况的发生呢&#xff1f;本文将对此进行深入解析&#xff0c;帮助大家揭开这一…

音视频入门基础:MPEG2-PS专题(2)——使用FFmpeg命令生成ps文件

通过FFmpeg命令可以将mp4文件转换为ps文件。由于ps文件对应的FFInputFormat结构为&#xff1a; const FFInputFormat ff_mpegps_demuxer {.p.name "mpeg",.p.long_name NULL_IF_CONFIG_SMALL("MPEG-PS (MPEG-2 Program Stream)"),.p.flags …

【数据结构与算法】单向链表

一、什么是链表 链表由一系列节点组成&#xff0c;每个节点都包含一个 data 域&#xff08;存放数据&#xff09;和一个 next 域&#xff08;指向下一节点&#xff09;。链表中的节点可以按照任意顺序存放在内存中&#xff0c;它们之间并不连续。每个节点都记录了下一个节点的地…

【计组】例题课后题

第一章 计算机如何区分指令和数据&#xff1f; 一般来讲&#xff0c;在取指周期中从内存读出的信息是指令流,它流向控制器&#xff1b;而执行周期中从内存读出的信息流是数据流,它由内存流向运算器。 从存放位置看&#xff0c;从代码段取出的是指令流&#xff0c;从数据…

一网多平面

“一网多平面”是一种网络架构概念&#xff0c;具体指的是在一张物理网络之上&#xff0c;逻辑划分出“1N”个平面。以下是对“一网多平面”的详细解释&#xff1a; 定义与构成 01一网多平面 指的是在统一的物理网络基础设施上&#xff0c;通过逻辑划分形成多个独立的网络平面…

跨语言数据格式标准化在 HarmonyOS 开发中的实践

文章目录 前言数据格式标准化的意义数据传递中的痛点标准化的优势 JSON 与 Protocol Buffers 的比较JSONProtocol Buffers HarmonyOS 跨语言数据传递示例示例代码&#xff1a;定义 Protocol Buffers 消息格式生成 Java 和 C 代码示例代码&#xff1a;Java 端序列化与传递数据C …