《白话C++》第10章 STL和boost,Page74 10.4.4 std::unique_ptr

std::unique_ptr可以同时处理普通指针和指向数组的指针:

unique_ptr像是auto_ptr的功能改良版

第一个改进就是可以管理指向单一对象的指针,也可以管理指向连续对象(数组)的指针。

第二个,unique_ptr改进的是,auto_ptr最大的黑暗面:“偷偷摸摸”的,看似“复制”其实却是“转移”的操作。

std::unique_ptr<S> s1(new S);
std::unique_ptr<S> s2(s1); //Error, 拷贝构造,不行
std::unique_ptr<S> s3 = s1; //Error, 直接赋值,也不行

s2想以s1为模复制,失败;s3使用赋值操作(但通常会被优化成拷贝构造)也失败。

unique_ptr对象将裸指针看得相对紧一点,不容易发生突然就转交给别的对象的事情。

如果在使用过程中确实需要转移,方法一是让源对象清晰明确地主动释放:

std::unique_ptr<S> s1(new S);
//主动声明'放手'后,可以转移至别人
std::unique_ptr<S> s4(s1.release());

s1主动调用release()方法,返回放手后的裸指针,然后作为另一个unique_ptr对象的构造入参,实现所有权转移。

另一个方法是使用转移语义,调用标准库的move()方法:

std::unique_ptr<S> s1(new S);
//支持标准库转移函数
std::unique_ptr<S> s4 = std::move(s1); 

从字面上看,无论是自愿的“release()(释放)”还是被外部强行“move()”(转移),语义都非常明确,不容易误解误用。

一旦主动释放或被转移,原unique_ptr对象所拥有的裸指针就是空指针nullptr。原裸指针的管理责任,由接手者负责,这些功能和auto_ptr并无两样。

unique_ptr砍掉了一些功能(禁止拷贝构造和赋值复制),然后正好有函数release(),

unique_ptr明确(采用“= delete”的方法)禁用了拷贝构造和复制操作,从而杜绝了auto_ptr面子上在“复制”,私下里却在“转移”的危险行为;但是如果碰上看起来是在复制但其实是在转移的安全行为,unique_ptr却又能放宽政策。

unique_ptr是在对“转移”语义有良好定义的C++11新标的背景下引入的智能指针,所以它也能“识别”出哪些转移行为是安全可执行的,哪些是危险不能偷着来的。

先看危险的:

std::unique_ptr up1(new int);
std::unique_ptr up2 = up1;//不允许

为什么不能通过第二行代码,将up1所管理的裸指针,转移给up2?因为up1此时也还活着,就这样借着第二行代码(这可是一句复制操作)转移出去,也许up1是自愿的,可这也许这根本就是某些程序员技艺不精或一时糊涂写错的啊(程序员本意也许就是想复制)。万一是后者,会让up1有冤无处说,最终搞垮整个程序。

这种情况下,unique_ptr要求程序员明确指出,我是要转移:

std::unique_ptr up2 = std::move(up1); //OK!

一切都要“明确!明确!”

再来看另一个危险情况:

void UsePtr(std::unique_ptr<int> aup)
{assert(aup);cout << *aup << endl;
}

注意,函数入参aup不是引用,也不是指针(原始指针),所以想调用该函数,必须复制一个unique_ptr <int> 的对象传进去,但这是被禁止的:

void test()
{std::unique_ptr <int> upi(new int(0));UsePtr(upi); //编译失败
}

编译失败,因为upi无法以传值(复制)的方式,传给UsePtr。根据需要,有两种解决方法,一是修改UsePtr,将其入参改为引用或指针,以前者为例:

void UsePtr2(std::unique_ptr<int>& aup)

这是常见的需求,即指针还是那个指针。如果确实需要将调用处的智能指针转移给函数入参,那就回到使用move的方法:

void test()
{std::unique_ptr <int> upi(new int(0));//转移之后,upi对象所拥有的裸指针就变为空UsePtr(std::move(upi)); //编译通过!
}

此时调用处的代码明确写着“move”,这也是对调用者最好的提醒:你定义的upi所管理的内存,已经被转移走了,因此upi内部裸指针已经是nullptr了,请不要再访问它了。这个例子也演示了如何使用std::unique_ptr作为函数入参

安全的情况:

如果一个对象(通常是匿名对象)马上就要“死了”,那么就可以大大方方地把这个对象所占用的内存转移过来,典型的如一个函数返回的临时对象:

std::unique_ptr <int> CreatePtr(int value)
{std::unique_ptr <int> result(new int(value));return result;
}void test2()
{//看似复制,其实转移std::unique_ptr <int> r = CreatePtr(1000000); 
}

函数的返回值,被放在函数调用栈找那个,如果它不是指针,也不是引用,那就意味着它很快就会消亡,因此它就是一个临时对象。test2()中,变量r就从容地“转移”走了CreatePtr()返回的unique_ptr所拥有的裸指针。如果你不放心编译器,或者有道德洁癖,可以坚持这样写:

std::unique_ptr <int> r2 = std::move(CreatePtr(1000000));

这个例子也用于演示如何使用std::unique_ptr作为函数返回值

unique_ptr语义明确,并且也方便在函数建传递,因此它进入了标准库。

我们建议,如果只需要一个有长生命周期的堆对象,并不需要多个指针同时指向该对象时,就可以使用unique_ptr管理。

再次体现:unique_ptr也可以用来管理一堆“堆对象”(数组)。

当unique_ptr在管理一个堆数组时,有没有办法从它身上得知所管理的数组包含了几个元素?

原始的堆数组,它其实就是一个指针,除了靠自行记忆,当我们手上有一个指针,除非搞“黑科技”,否则我们还真不能识别出它是指向一个对象,还是指向一组对象,如果是后者,更无法得知所指向的数组有多大。

让unique_ptr负责管理一个堆数组时,它同样没法给出数组大小的信息

【小提示】:如何临时从智能指针对象上取得裸指针

boost::scoped_ptr和std::unique_ptr都提供get()成员以返回其管理的裸指针(只是返回,并没有像release()那样交出管理权)。

由于unique_ptr同时也能管理堆数组,此时get()返回的指针,就是指向该数组(一块连续内存)的指针。

除了要和纯C的接口对接,否则我们很少有调用get()以取得裸指针的需要。

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

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

相关文章

【qt创建线程两种方式】

QT使用线程的两种方式 1.案例进度条 案例解析&#xff1a; 如图由组件一个进度条和三个按钮组成&#xff0c;当点击开始的时候进度条由0%到100%&#xff0c;点击暂停&#xff0c;进度条保持之前进度&#xff0c;再次点击暂停变为继续&#xff0c;点击停止按钮进度条停止。 案…

【C++学习手札】多态:掌握面向对象编程的动态绑定与继承机制(深入)

&#x1f3ac;慕斯主页&#xff1a;修仙—别有洞天 ♈️今日夜电波&#xff1a;世界上的另一个我 1:02━━━━━━️&#x1f49f;──────── 3:58 &#x1f504; ◀️ ⏸ ▶️ ☰ &am…

速卖通新店测评需要提前准备哪些资料?

在速卖通平台上&#xff0c;新店的起步往往充满挑战。缺乏活动支持、流量稀少&#xff0c;使得许多新卖家在90天内达成60单业绩的目标前望而却步。然而&#xff0c;有一种策略能够帮助卖家快速步入正轨——那就是测评。不过&#xff0c;对于测评&#xff0c;许多新手卖家存在误…

【牛客面试必刷TOP101】Day23.BM27 按之字形顺序打印二叉树和BM30 二叉搜索树与双向链表

作者简介&#xff1a;大家好&#xff0c;我是未央&#xff1b; 博客首页&#xff1a;未央.303 系列专栏&#xff1a;牛客面试必刷TOP101 每日一句&#xff1a;人的一生&#xff0c;可以有所作为的时机只有一次&#xff0c;那就是现在&#xff01;&#xff01;&#xff01;&…

如何将阿里云服务器迁移

&#x1f4d1;前言 本文主要是如何将阿里云服务器迁移实现数据转移的文章&#xff0c;如果有什么需要改进的地方还请大佬指出⛺️** &#x1f3ac;作者简介&#xff1a;大家好&#xff0c;我是青衿&#x1f947; ☁️博客首页&#xff1a;CSDN主页放风讲故事 &#x1f304;每日…

Conda管理Python不同版本教程

Conda管理Python不同版本教程 目录 0.前提 1.conda常用命令 2.conda设置国内源&#xff08;以添加清华源为例&#xff0c;阿里云源同样&#xff09; 3.conda管理python库 4.其它 不太推荐 pyenv管理Python不同版本教程&#xff08;本人另一篇博客&#xff0c;姊妹篇&…

如何测试Web网页的兼容性测试?

测试Web网页的兼容性是一个重要的步骤&#xff0c;以确保网站在不同的浏览器、操作系统和设备上都能正常工作。以下是一些步骤和方法来测试网页的兼容性&#xff1a; 01. 确定目标平台 首先&#xff0c;确定要测试的目标浏览器、操作系统和设备。这通常包括最常用的浏览器&…

【详解】图的概念和存储结构(邻接矩阵,邻接表)

目录 图的基本概念&#xff1a; 图的存储结构 邻接矩阵&#xff08;GraphByMatrix&#xff09;&#xff1a; 基本参数&#xff1a; 初始化&#xff1a; 获取顶点元素在其数组中的下标 &#xff1a; 添加边和权重&#xff1a; 获取顶点的度&#xff1a; 打印图&#xf…

【数据结构与算法】递归、回溯、八皇后 一文打尽!

&#x1f389;&#x1f389;欢迎光临&#x1f389;&#x1f389; &#x1f3c5;我是苏泽&#xff0c;一位对技术充满热情的探索者和分享者。&#x1f680;&#x1f680; &#x1f31f;特别推荐给大家我的最新专栏《数据结构与算法&#xff1a;初学者入门指南》&#x1f4d8;&am…

中科院一区论文复现,改进蜣螂算法,Fuch映射+反向学习+自适应步长+随机差分变异,MATLAB代码...

本期文章复现一篇发表于2024年来自中科院一区TOP顶刊《Energy》的改进蜣螂算法。 论文引用如下&#xff1a; Li Y, Sun K, Yao Q, et al. A dual-optimization wind speed forecasting model based on deep learning and improved dung beetle optimization algorithm[J]. Ener…

VScode主题推荐-个人使用

在介绍主题之前&#xff0c;先看一下怎么在 VS Code 中切换主题。VS Code 提供了便捷的快捷命令面板&#xff0c;里边各种常用的主题都可以搜索到&#xff0c;包括更换主题。打开快捷命令面板的快捷键是&#xff1a; Command/Ctrl shift p 下载安装主题需要打开VScode&…

思迈特再获国家权威认证:代码自主率98.78%

日前&#xff0c;思迈特软件自主研发的商业智能与数据分析软件&#xff08;Smartbi Insight&#xff09;通过中国赛宝实验室&#xff08;工业和信息化部电子第五研究所&#xff09;代码扫描测试&#xff0c;Smartbi Insight V11版本扫描测得代码自主率为98.78%的好成绩&#xf…