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

news2025/1/19 20:26:14

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.coloradmin.cn/o/1455332.html

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

相关文章

huggingface入门玩耍LLM Starter

huggingface入门玩耍LLM Starter huggingface-cli 下载model 下载 本人macos系统&#xff0c;以下可参考 huggingface-cli 下载 brew install huggingface-climodel 下载 以 chatglm-6b 为例 huggingface-cli download --token hf_*** --resume-download THUDM/chatglm-6b-i…

C/C++ BM7 链表中环的入口结点

文章目录 前言题目解决方案一1.1 思路阐述1.2 源码 解决方案二2.1 思路阐述2.2 源码 总结 前言 BM6里面使用了双指针法和哈希的方式来查找环&#xff0c;BM7相对于BM6只多了一个查找第一个重复地址的过程。个人认为是用哈希是最简单&#xff0c;C11标准的set或者map。 题目 给…

洛谷 P1150 Peter 的烟

参考代码and代码解读 #include<iostream> using namespace std; int main() { int n,k,nonu; //n烟的数量&#xff0c;k需要多少根烟头换一支烟&#xff0c;nonu记录烟头的个数 cin>>n>>k; int sumn; //一开始就能吸n支烟 nonusum; …

C++友元->全局函数做友元、类做友元、成员函数做友元

全局函数做友元代码&#xff1a; #include<iostream> using namespace std; #include<string> //建筑物类 class Building { //告诉编译器 goodGay全局函数 是 Building类的好朋友&#xff0c;可以访问类中的私有内容 friend void goodGay(Building * bu…

linux kernel 内存踩踏之KASAN_HW_TAGS(MTE)(三)

一、背景 linux kernel 内存踩踏之KASAN&#xff08;一&#xff09;_kasan版本跟hasan版本区别-CSDN博客 linux kernel 内存踩踏之KASAN_SW_TAGS&#xff08;二&#xff09;-CSDN博客 最后来介绍一下KASAN_HW_TAGS&#xff0c;ARM64上就是MTE&#xff0c;这个特性在ARMv8.5支…

python in Vscode

背景 对于后端的语言选择&#xff1a; python&#xff0c;java&#xff0c;JavaScript备选。 选择Python 原因&#xff1a;可能是非IT专业的人中&#xff0c;会Python的人比较多。 目的 之前使用的IDE是VSCODE&#xff0c;在WSL的环境下使用。现在需要在在WSL的VSCODE下使…

分享几个丝滑oled代码

最近一段业余时间在捣鼓esp32&#xff0c;发现对于一个搞diy的来说&#xff0c;它的生态&#xff0c;不管是开发环境、氛围还是可玩度都是独一挡的&#xff0c;国内外基于此的扩展真是太多了&#xff0c;找了几个通过按键/旋钮进行0.96寸OLED控制的案例&#xff0c;超级丝滑&am…

【论文解读】Latency-Aware Collaborative Perception

Latency-Aware Collaborative Perception 摘要引言方法SystemSyncNet 实验 摘要 协作感知最近显示出提高单智能体感知感知能力的巨大潜力。现有的协同感知方法通常考虑理想的通信环境。然而&#xff0c;在实践中&#xff0c;通信系统不可避免地存在延迟问题&#xff0c;导致安…

2月16日openai又出了什么大招呢?

2024年2月16日通过google trends可以发现“sora”被大量的搜索与关注。那么什么是“sora”呢&#xff1f; Sora是OpenAI发布的一款文本到视频的AI模型&#xff0c;它能够根据文本指令生成逼真和富有想象力的场景。Sora 可以创建长达 60 秒的视频&#xff0c;其中包含高度详细的…

后端扫盲系列 - vue入门指南

vue特点 组件化&#xff1a;用户界面分解为可重用的组件&#xff0c;这些组件可以使开发的页面更加模块化和可维护双向数据绑定&#xff1a;vue提供了一种轻松绑定数据和DOM元素之间的机制&#xff0c;意味着数据发送变化时&#xff0c;视图会自动更新&#xff0c;反之亦然虚拟…

糟糕,接口被刷了,怎么办?

前言 在面试时&#xff0c;经常会被问一个问题&#xff1a;如何防止别人恶意刷接口&#xff1f; 这是一个非常有意思的问题&#xff0c;防范措施挺多的。今天这篇文章专门跟大家一起聊聊&#xff0c;希望对你会有所帮助。 1 防火墙 防火墙是网络安全中最基本的安全设备之一&…

每周AI新闻(2024年第7周)OpenAI发布视频生成模型Sora | 谷歌推出Gemini 1.5 | 英伟达公开超级计算机

这里是陌小北&#xff0c;一个正在研究硅基生命的碳基生命。正在努力成为写代码的里面背诗最多的&#xff0c;背诗的里面最会写段子的&#xff0c;写段子的里面代码写得最好的…厨子。 每周日解读每周AI大事件。 这一周&#xff0c;国外各厂真是不让我们消停儿过年呐&#xf…

抑郁症测试丨焦虑症测试小程序源码

这是一个考验智力,心里上面的一个测试游戏 支持多种测试方法比如有: 智商测试丨情商测试 性格测试丨爱情测试 抑郁症测试丨焦虑症测试 心理压力测试丨生活满意度测试 通过不同的测试,来检查你的智力,情商等等 通过发行自己的不住来弥补自己的不足所以这就是为什么小编会…

Linux系统——防火墙Firewalld

目录 一、firewalld介绍 1.归入zone顺序 2.firewalld zone分类 3.预定义服务 二、图形化操作 1.打开firewalld图形化界面 2.以http服务为例&#xff0c;打开httpd服务 3.修改端口号 三、命令行配置 1.基础配置 2.查看现有firewalld设置 3.设置查看默认区 4.添加源…

Java集合篇之深度解析Queue,单端队列、双端队列、优先级队列、阻塞队列

写在开头 队列是Java中的一个集合接口&#xff0c;之前的文章已经讲解了List和Set&#xff0c;那么今天就来唠一唠它吧。队列的特点&#xff1a;存储的元素是有序的、可重复的。 队列的两大接口Queue vs Deque Queue 是单端队列&#xff0c;只能从一端插入元素&#xff0c;另…

【c++】STL之stack和queue详解

> 作者简介&#xff1a;დ旧言~&#xff0c;目前大二&#xff0c;现在学习Java&#xff0c;c&#xff0c;c&#xff0c;Python等 > 座右铭&#xff1a;松树千年终是朽&#xff0c;槿花一日自为荣。 > 目标&#xff1a;掌握stack和queue库&#xff0c;了解deque库 >…

linux系统,使用cmake 编译C++代码,如何生成静态库。

linux系统&#xff0c;使用cmake 编译C代码&#xff0c;如何生成静态库。 xlog文件夹下面是生成静态库所需要的文件。 test_xlog文件夹下面是调用静态库所需要的文件。 xlog文件夹下的文件&#xff1a; 1、CMakeLists.txt #CMakeLists.txt # 设置:版本 cmake_minimum_req…

[playbook] playbook运用

一、复习playbook剧本 --- - name: first play for install nginx #设置play的名称gather_facts: false #设置不收集facts信息hosts: webservers:dbservers #指定执行此play的远程主机组remote_user: root #指定执行此play的用…

自建AWS S3存储服务

unsetunset前言unsetunset AWS S3&#xff08;Amazon S3&#xff0c;全名为亚马逊简易存储服务&#xff09;&#xff0c;是亚马逊公司利用其亚马逊网络服务系统所提供的网络在线存储服务。我常用的很多SaaS服务中提供的文件存储功能&#xff0c;底层也都是AWS S3&#xff0c;比…

Vite 构建流程大揭秘:快速构建前端项目的秘密武器

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…