第7章 Page446~449 7.8.9智能指针 std::unique_ptr

“unique_ptr”是“独占式智能指针”

名字透露身份,“unique_ptr”是“独占式智能指针”。使用它管理前面的O类指针:

演示1:

例中 p 是一个智能指针。其中的“<O>”指明它所指向的数据类型是“O”。除了创建方法不太一样,以及不用手工释放之外,智能指针使用上和它所管理的裸指针基本一样。

如果健忘而负责任的程序员,忘了p是智能指针,写出“delete p”这样的代码,也不用怕,编译器会就出这个错误。

例中的裸指针同样没有名字,在调用智能指针对象的构造函数是,直接使用new生成。这是推荐的做法,这样做的好处是,防止有人故意捣乱。

构建“unique_ptr”对象是,只能采用“构造式初始化”,不允许采用“赋值式初始化”

如果手头上确实已经有了一个裸指针,临时需要交给智能指针来管理,也是支持的:

O* po = new O();
std::unique_ptr <O> p(po);

这里有个细节,即构建“unique_ptr”对象是,只能采用“构造式初始化”,不允许采用“赋值式初始化”的语法:

std::unique_ptr <O> p2 = new O();//编译出错
O* po = new O();
std::unique_ptr <O> p = po; //同样编译出错

这是刻意的设计,不允许将一个裸指针使用“=”赋值给智能指针。良好的智能指针就是这样一个纠结的设计:既要让它用起来就像一个裸指针,又要在关键的地方提醒一下你,它不是一个真的指针

智能指针也可以有“空指向”的状态,构建时不传入裸指针即可:

std::unique_ptr <O> p; //空指向的智能指针
if(p == nullptr) //成立
{
    cout << "p is a nullptr" << endl;
}
if(!p)//也成立
{
    cout << "not p" << endl;
}
演示unique_ptr初始还方式:

以上都是让智能指针尽量用起来像裸指针的设计。背后的实现手段还是“重载操作符”。

智能指针当然可以改变指向,

只是同样不能使用“=”将裸指针赋给智能指针右值必须同样是智能指针

std::unique_ptr <O> p; //空指向的智能指针
...
p = std::unique_ptr <O> (new O);//不能省略为“p = new O”

但是这样写显得很冗长,可以改用“unique_ptr”带参版“reset(...)”的方法,用于改变一个“unique_ptr”的指向:

O* src1 = new O;
O* src2 = new O;
std::unique_ptr <O> p(src1); //先管理src1
...
p.reset(src2); //改为管理src2,改之前,src1将被释放
演示智能指针改变指向:

改变一个“unique_ptr”的指向,如果该智能指针不是空指向,会先释放原来管理的裸指针,再接管新的裸指针。这中间隐藏了一个风险,即新指向和旧指向,必须确保不是同一个对象:

O* o = new O;
std::unique_ptr <O> p(o); //p管理着o
p = std::unique_ptr <O>(o); //p改变指向,但其实还是指向o。

003行执行过程是这样的:在改变指向之前,p要先干掉当前所管理的裸指针,也就是o。然后再管理新的裸指针,不幸的是,这个所谓的“新”的裸指,仍然是o,刚刚被干掉的o。编译器无法帮我们识别这样的问题。

“unique_ptr”的独占性:

一个裸指针不能由多个“std::unique_ptr”管理,但编译器挡不住程序员刻意将一个裸指针交给多个“unique_ptr”管理,编译器无法阻止你干出“一女多嫁”的事情:

O* o = new O; //一个裸指针
std::unique_ptr <O> p1(o); //交给p1管
std::unique_ptr <O> p2(o); //又交给p2管

错误将在运行时发生,本例中由于O结构没有任何成员数据,所以发生这个错误的程序可能不会挂掉,但错误确实发生了,能够从屏幕输出o被释放两次

演示“一女多嫁”:

能不能“改嫁”呢?

O* o = new O; //还是一个裸指针
std::unique_ptr <O> p1(o); //先交给p1
std::unique_ptr <O> p2 = p1; //然后由p1转交个p2?
//std::unique_ptr <O> p2(p1); //同上,但使用更正规构造式初始化

逻辑上是说的通的,具体做法可以是:p1让出o,让给p2; p1变成空指向,并且C++中已经被标为“废弃”,但暂时还可使用老版本的智能指针“std::auto_ptr”,就是这么设计的。但事实003行或004行,都将编译失败。

C++ 11认为,这样偷偷修改源对象的做法太隐晦了,程序员难以直观地通过阅读代码“想起”这过程中源对象(例中的p1)变成空指向了。

演示“改嫁”:

转移函数std::move()

如果确实需要转移管理全,有两种方法。一种是明确使用C++11提供的转移函数:

std::unique_ptr <O> p2 = std::move(p1); //OK
//也可以std::unique_ptr <O> p2(std::move(p1)); //OK

包装一层“std::move”的调用,已明提示阅读者,p1的内容被“转移(move)”了,这就是“std::unique_ptr”作为“独占式”智能指针的最经典表现,即:不能将独占式智能指针A,赋值给独占式智能指针B,只能做转移。源方失去对裸指针的管理权,目标方获得。一失一得,裸指针的管理权仍然只属一方。

演示std::move():

可以看到,裸指针只被释放了一次

release()方法:

实现转移管理权的另一种做法,是通过“std::unique_ptr”提供的“release()”方法。该方法可让一个智能指针“放手”它所“爱过”的裸指针:

std::unique_ptr <O> p(new O());
O* o = p.release(); //“吐出”所管理的裸指针

p吐出管理对象之后,自然变成空指向,而程序员手上拿着一个裸指针,又得考虑何时delete这个o对象。或者,干脆把它交给另一个智能指针管理吧,这是一个“迂回”的转移过程。

演示release():

get()方法:

如果临时需要得到裸指针,但又不希望智能指针撒手不管,可以使用“std::unique_ptr”的“get()”方法:

std::unique_ptr <O> p(new O());
O* o = p.get();
演示get()方法:

unique_ptr变成空指向:unique_ptr被赋值裸指针的一个特例

赋裸指针:

如果想让一个“unique_ptr”变成空指向,倒是可以直接为它赋值nullptr,尽管前面我们刚说过不允许为“unique_ptr”赋值裸指针(而理论上nullptr是裸指针),这算是一个特例。

std::unique_ptr <O> p(new O());
...
p = nullptr;
演示赋裸指针:

reset()方法:

或者也可以使用“std::unique_ptr”的无入参版本的"reset()"方法:

p.reset();//让p变成空指向
演示reset方法:

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

SAP PP学习笔记- 豆知识02 - 品目要谁来维护?怎么决定更不更新品目的数量金额?

其实都是在品目类型的Customize中设定的。 咱们这里简单试着说一下什么场景使用。 1&#xff0c;SAP中品目有很多View&#xff0c;都要由哪些部门来维护呢&#xff1f; 其实就是谁用谁维护呗。 在新建一个品目的时候&#xff0c;品目Type本身就决定了该品目要由哪些部门来维…

gem5 garnet 合成流量: packet注入流程

代码流程 下图就是全部. 剩下文字部分是细节补充,但是内容不变: bash调用python,用python配置好configuration, 一个cpu每个tick运行一次,requestport发出pkt. bash 启动 python文件并配置 ./build/NULL/gem5.debug configs/example/garnet_synth_traffic.py \--num-cpus…

【C++】---类和对象(上)入门

一、类的定义 1.那么众所周知&#xff0c;C语言是面向过程的&#xff0c;关注的是过程&#xff0c;分析出求解的步骤&#xff0c;通过函数的调用来逐步解决问题 2.而C是基于面向对象的&#xff0c;关注的是对象&#xff0c;将一件事情拆分成不同的对象&#xff0c;靠对象之间交…

消息队列RabbitMQ-使用过程中面临的问题与解决思路

消息队列在使用过程中会出现很多问题 首先就是消息的可靠性&#xff0c;也就是消息从发送到消费者接收&#xff0c;消息在这中间过程中可能会丢失 生产者到交换机的过程、交换机到队列的过程、消息队列中、消费者接收消息的过程中&#xff0c;这些过程中消息都可能会丢失。 …

【数据结构】LRU Cache

文章目录 LRUCache LRUCache 1. LRUCache是一种缓存的替换技术&#xff0c;在CPU和main memory之间根据计算机的局部性原理&#xff0c;往往会采用SRAM技术来构建CPU和主存之间的高速缓存&#xff0c;DRAM(dynamic random access memory)用于构建主存&#xff0c;LRUCache这种…

【正点原子STM32】TIMER 定时器(软件定时原理、定时器定时原理、分类和特性、基本定时器(影子寄存器和U事件和UI中断))

一、定时器概述 1.1、软件定时原理1.2、定时器定时原理1.3、STM32定时器分类1.4、STM32定时器特性表1.5、STM32基本、通用、高级定时器的功能整体区别 二、基本定时器 2.1、基本定时器简介2.2、基本定时器框图2.3、定时器计数模式及溢出条件2.4、定时器中断实验相关寄存器2.…

【数据结构】二叉树的三种遍历

目录 一、数据结构 二、二叉树 三、如何遍历二叉树 一、数据结构 数据结构是计算机科学中用于组织和存储数据的方式。它定义了数据元素之间的关系以及对数据元素的操作。常见的数据结构包括数组、链表、栈、队列、树、图等。 数组是一种线性数据结构&#xff0c;它使用连续…

[Vue warn]: Duplicate keys detected: ‘1‘. This may cause an update error.

[Vue warn]: Duplicate keys detected: ‘1‘. This may cause an update error.——> Vue报错&#xff0c;key关键字不唯一&#xff1a; 解决办法&#xff1a;修改一下重复的id值&#xff01;&#xff01;&#xff01;

C#系列-使用 Minio 做图片服务器实现图片上传 和下载(13)

1、Minio 服务器下载和安装 要在本地安装和运行 MinIO 服务器&#xff0c;你可以按照以下 步骤进行操作&#xff1a; 1. 访问 MinIO 的官方网站&#xff1a;https://min.io/&#xff0c;然后 点击页面上的”Download”按钮。 2. 在下载页面上&#xff0c;选择适合你操作系统的 …

(16)Hive——企业调优经验

前言 本篇文章主要整理hive-3.1.2版本的企业调优经验&#xff0c;有误请指出~ 一、性能评估和优化 1.1 Explain查询计划 使用explain命令可以分析查询计划&#xff0c;查看计划中的资源消耗情况&#xff0c;定位潜在的性能问题&#xff0c;并进行相应的优化。 explain执行计划…

[C#] 如何调用Python脚本程序

为什么需要C#调用python&#xff1f; 有以下几个原因需要C#调用Python&#xff1a; Python拥有丰富的生态系统&#xff1a;Python有很多强大的第三方库和工具&#xff0c;可以用于数据科学、机器学习、自然语言处理等领域。通过C#调用Python&#xff0c;可以利用Python的生态系…

HiveSQL——统计当前时间段的有客人在住的房间数量

注&#xff1a;参考文章&#xff1a; HiveSQL一天一个小技巧&#xff1a;如何统计当前时间点状态情况【辅助变量累计变换思路】_sql查询统计某状态出现的次数及累计时间-CSDN博客文章浏览阅读2k次&#xff0c;点赞6次&#xff0c;收藏8次。本文总结了一种当前时间点状态统计的…

【JAVA-Day86】守护线程

守护线程 守护线程摘要引言1. 了解守护线程&#xff1a;它是什么&#xff1f;&#x1f47b;特点和用途示例代码 2. 为何我们需要守护线程&#xff1f;&#x1f47b;辅助性任务处理不阻止程序的正常运行重要的清理工作示例代码&#x1f4da; 3. 如何创建和管理守护线程&#xff…

QT 工具栏 状态栏 停靠部件 核心部件

添加/删除工具栏 删除工具栏方法和删除菜单栏方法一样&#xff0c;不过工具栏可以有多个&#xff0c;所以每次右键MainWindow对象&#xff0c;都可以看到添加工具栏的选项。 工具栏添加动作 新添加的QAction对象会在动作编辑器里找到&#xff08;Action Editor&#xff09;&a…

Java毕业设计-基于springboot的学院物资管理系统-第73期

获取源码资料&#xff0c;请移步从戎源码网&#xff1a;从戎源码网_专业的计算机毕业设计网站 项目介绍 基于springboot的学院物资管理系统&#xff1a;前端thymeleaf、jquery、layui&#xff0c;后端 maven、springmvc、spring、mybatis&#xff0c;有配套报告文档&#xff…

微信小程序的疑惑总结

未解决&#xff1a; 1.storebindings 这里的storebindings是什么 2.空行怎么写&#xff1f; 我用这个<text>\n</text>写&#xff0c;在模拟器上好使&#xff0c;在真机上显示\n 解决方法&#xff1a;在组件里写class类名&#xff0c;wxss里面改高度 已解决&am…

LD-802D-X6

LD-802D-X6足浴按摩器&#xff0c;买个给老人家&#xff0c;解决泡脚越泡越冷&#xff0c;调节温度和定式问题&#xff0c; 按摩功能老人体验说太痒&#xff0c;转太快了&#xff0c;哈哈 下面是安装步骤使用说明 其实这包零件就是安装底部4个轮子&#xff0c;4个轮子的中间滚…

【分享】图解ADS+JLINK调试ARM

文章是对LPC2148而写的&#xff0c;但是对三星的44B0芯片同样适用&#xff0c;只需要在选择时将相应的CPU选择的S3C44B0就可以了。 JLINK在ADS下调试心得 前两天一个客户用jlink在ADS下调试LPC2148总报错&#xff0c;这个错误我之前在调试LPC2200的时候也碰到过&#xff0c;后…

Nuxt3+Vue3(Composition API)+TS+Vite+Ant Design Vue 搭建

最近官网搭建选择了nuxtjs&#xff0c;由于框架更新了&#xff0c;其中语法也有很多变化&#xff0c;中间遇到了一些问题点做下总结。 nuxt3官方文档地址&#xff1a;https://nuxt.com/docs/getting-started/installation 安装 在安装Nuxt3之前&#xff0c;你需要保证你的nod…

【AIGC】Stable Diffusion的常见错误

Stable Diffusion 在使用过程中可能会遇到各种各样的错误。以下是一些常见的错误以及可能的解决方案&#xff1a; 模型加载错误&#xff1a;可能出现模型文件损坏或缺失的情况。解决方案包括重新下载模型文件&#xff0c;确保文件完整并放置在正确的位置。 依赖项错误&#x…