C++智能指针:unique_ptr详解
文章目录
- unique_ptr描述
- 声明
- 作用
- 函数指针描述
- 总结
unique_ptr描述
声明
头文件:<memory>
模版类:
- 默认类型
template <class T, class D = default_delete<T>> class unique_ptr
- 数组类型
template <class T, class D> class unique_ptr<T[],D>;
作用
与shared_ptr最大的区别即是unique_ptr不能够共享同一个地址,它对地址是独占得。当unique_ptr对象的生命周期结束,则它所引用的地址空间也会被释放。
一个unique_ptr对象主要包含两个部分
- 一个存储指针:主要用来管理对象的地址空间。它是在构造函数中分配的地址,并且能够通过赋值运算符以及reset成员函数进行地址空间的重新指向。并且可以通过get和release成员变量进行单独访问,获取unique_ptr对象的地址空间。
- 一个存储删除器:删除器为一个可以被调用的对象。主要被用来删除unique_ptr对象的地址空间。同时能够使用赋值运算符进行当前对象的更改,并通过get_deleter成员函数进行单独访问。
函数指针描述
- 构造函数
输出如下://unique_ptr constructor example #include <iostream> #include <memory>int main () {std::default_delete<int> d;//默认为空std::unique_ptr<int> u1;//使用null初始化指针,仍然为空std::unique_ptr<int> u2 (nullptr);//正常初始化std::unique_ptr<int> u3 (new int);//存储指针正常初始化,之后并初始化删除器的值,所以不为空std::unique_ptr<int> u4 (new int, d);//存储指针正常初始化,之后删除器使用默认的构造函数进行初始化,所以unique_ptr又为空了std::unique_ptr<int> u5 (new int, std::default_delete<int>());std::unique_ptr<int> u6 (std::move(u5));std::unique_ptr<int> u7 (std::move(u6));std::unique_ptr<int> u8 (std::auto_ptr<int>(new int));std::cout << "u1: " << (u1?"not null":"null") << '\n';std::cout << "u2: " << (u2?"not null":"null") << '\n';std::cout << "u3: " << (u3?"not null":"null") << '\n';std::cout << "u4: " << (u4?"not null":"null") << '\n';std::cout << "u5: " << (u5?"not null":"null") << '\n';std::cout << "u6: " << (u6?"not null":"null") << '\n';std::cout << "u7: " << (u7?"not null":"null") << '\n';std::cout << "u8: " << (u8?"not null":"null") << '\n';return 0; }
u1: null u2: null u3: not null u4: not null u5: null u6: null u7: not null u8: not null
- 析构函数;如果对象为空的unique_ptr,即使用get()==nullptr,则析构函数无法产生作用
否则会正常删除对象,就像get_deleter()
函数一样
输出如下:// unique_ptr destructor example #include <iostream> #include <memory>int main () {auto deleter = [](int*p){delete p;std::cout << "[deleter called]\n";};std::unique_ptr<int,decltype(deleter)> foo (new int,deleter);std::cout << "foo " << (foo?"is not":"is") << " empty\n";return 0; // [deleter called] }
foo is not empty [deleter called]
operator=
输出如下:// unique_ptr::operator= example #include <iostream> #include <memory>int main () {std::unique_ptr<int> foo;std::unique_ptr<int> bar;foo = std::unique_ptr<int>(new int (101)); // rvalue//std::move操作是将foo对象的地址以及空间内容转给bar,所以执行之后foo变为了empty//之所以使用std::move操作是因为unique_ptr对象地址空间只能被一个对象独享bar = std::move(foo); // using std::movestd::cout << "foo: ";if (foo) std::cout << *foo << '\n'; else std::cout << "empty\n";std::cout << "bar: ";if (bar) std::cout << *bar << '\n'; else std::cout << "empty\n";return 0; }
foo: empty bar: 101
std :: unique_ptr :: get
成员,改成员函数返回被管理的unique_ptr
对象,此函数的调用不会使unique_ptr释放指针的所有权(即,它仍然负责在某个时刻删除管理数据)。因此,此函数返回的值不得用于构造新的管理指针。为了活动存储指针,并且能够正常释放,则使用release()
成员函数
输出如下:// unique_ptr::get vs unique_ptr::release #include <iostream> #include <memory>int main () {// foo bar p// --- --- ---std::unique_ptr<int> foo; // nullstd::unique_ptr<int> bar; // null nullint* p = nullptr; // null null nullfoo = std::unique_ptr<int>(new int(10)); // (10) null null//这里经过std::move之后foo的地址以及内容转移给了barstd::cout << "foo: " << foo.get() << std::endl;bar = std::move(foo); // null (10) nullstd::cout << "foo: " << foo.get() << std::endl;std::cout << "bar: " << bar.get() << std::endl;p = bar.get(); // null (10) (10)*p = 20; // null (20) (20)p = nullptr; // null (20) nullfoo = std::unique_ptr<int>(new int(30)); // (30) (20) nullp = foo.release(); // null (20) (30)*p = 40; // null (20) (40)std::cout << "foo: ";if (foo) std::cout << *foo << '\n'; else std::cout << "(null)\n";std::cout << "bar: ";if (bar) std::cout << *bar << '\n'; else std::cout << "(null)\n";std::cout << "p: ";if (p) std::cout << *p << '\n'; else std::cout << "(null)\n";std::cout << '\n';delete p; // the program is now responsible of deleting the object pointed to by p// bar deletes its managed object automaticallyreturn 0; }
optionscompilationexecution foo: 0x817a10 foo: 0 bar: 0x817a10 foo: (null) bar: 20 p: 40
std :: unique_ptr :: release
通过改成员函数的返回值以及空指针来释放当前unique_ptr指针的所有权
当前调用并不会破坏管理对象,改成员函数不会删除对象,而需要其他实体在某个时候删除对象。如果想要强制删除对象,需要使用reset或者赋值运算符(std::move)
输出如下:// unique_ptr::release example #include <iostream> #include <memory>int main () {std::unique_ptr<int> auto_pointer (new int);int * manual_pointer;*auto_pointer=10;std::cout << " auto_pointer " << auto_pointer.get() << std::endl;manual_pointer = auto_pointer.release();std::cout << " auto_pointer " << auto_pointer.get() << std::endl;std::cout << " manual_pointer " << manual_pointer<< std::endl;// (auto_pointer is now empty)std::cout << "manual_pointer points to " << *manual_pointer << '\n';delete manual_pointer;return 0; }
auto_pointer 0x3afffa0auto_pointer 0manual_pointer 0x3afffa0 manual_pointer points to 10
std::unique_ptr::reset
void reset (pointer p = pointer()) noexcept;
破坏掉当前unique_ptr
对象,并且获取它所有权p,如果p是空的,则当前unique_ptr
对象也即为空
如果想要释放当前对象,并且并不破坏对象所指地址空间以及内容,则使用release
成员函数
输出如下:// unique_ptr::reset example #include <iostream> #include <memory>int main () {std::unique_ptr<int> up; // empty//reset之后 up之前对象所指空间已经被破坏,并重新接管up对象,分配新的地址空间up.reset (new int); // takes ownership of pointer//可以看到地址空间已经由之前的null变为重新分配的空间std::cout << *up << " " << up.get() << '\n';*up=5;std::cout << *up << " " << up.get() << '\n';up.reset (new int); // deletes managed object, acquires new pointer*up=10;std::cout << *up << " " << up.get() << '\n';up.reset(); // deletes managed objectreturn 0; }
0 0xd7dc70 5 0xd7dc70 10 0xd7dc90
std::unique_ptr::swap
交换对象空间以及内容,且并不破坏地址空间
输出如下:// unique_ptr::swap example#include <iostream>#include <memory>int main () {std::unique_ptr<int> foo (new int(10));std::unique_ptr<int> bar (new int(20));std::cout << "foo: " << *foo << " " << foo.get() << '\n';std::cout << "bar: " << *bar << " " << bar.get() << '\n';foo.swap(bar);std::cout << "foo: " << *foo << " " << foo.get() << '\n';std::cout << "bar: " << *bar << " " << bar.get() << '\n';return 0;}
foo: 10 0x2cd9ae0 bar: 20 0x2cd9b00 foo: 20 0x2cd9b00 bar: 10 0x2cd9ae0
总结
- shared_ptr地址空间无法被多个智能指针共享,当实际当前对象地址作用域结束,则改对象所占有地址空间将被释放
- 使用release成员函数可以转移unique_ptr队形的所有圈,即将unique_ptr对象转为非unique_ptr对象,并不破坏地址
- 使用
reset
会重置对象地址空间,并重新分配。会破坏地址空间 - 使用赋值元算符,和reset函数类似重新指定地址空间,同样会破坏地址空间
- unique_ptr对象的返回智能使用成员函数
get
相关文章:

川崎机器人示教盒维修_专业维修丹阳市KUKA库卡KRC2库卡C4主板维修{苏州罗韦维修}...
发那科机器人故障分析 发那科伺服放大器上LED指示灯故障维修大全_发那科机器人维修,FANUC机器人保养,伺服电机示教器减速器维修,驱动器维修,苏州发那科机器人维修,本文主要介绍了发那科伺服放大器上因故障而出现的各种…

js 文本反向排列显示
一次面试遇到这样的题目 反向输出“how are you” 解决方法 <script language"JavaScript">var message1"how are you";var message2"";for (countmessage1.length; count > 0; count--)message2message1.substring(count,count-1);doc…

2012年12月4期手机网页开发
最近主要做手机上页面的开发,主要框架是,手机安装客户端,加载主站手机应用页面,手机客户端配合主站功能实现本地扫描或重力感应的效果。 针对安卓系统,在开发和调试时发现如下问题:1路径错误&#…

zabbix4.0构建实录
【Nginx】 #wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo [rootcentos ~]# yum -y install zlib pcre pcre-devel openssl openssl-devel[rootcentos ~]# useradd -s /sbin/nologin nginx [rootzabbix-server ~]# yum install -y nginx 【M…

ceph-kvstore-tool 工具使用详解
文章目录简介使用总结简介 ceph-kvstore-tool工具是用来获取存放在leveldb或者rocksdb数据库中的键值元数据。并且该工具能够对kvstore中的数据进行配置,就像是对离线后的osd操作osd map一样 使用该工具,需要安装ceph-test-12.2.1.06-0.el7.centos.x86_…

springboot 订单重复提交_Spring Boot (一) 校验表单重复提交
一、前言在某些情况下,由于网速慢,用户操作有误(连续点击两下提交按钮),页面卡顿等原因,可能会出现表单数据重复提交造成数据库保存多条重复数据。存在如上问题可以交给前端解决,判断多长时间内不能再次点击保存按钮&a…

智能会议白板系统每日开发记录
智能会议白板系统,在开发过程中,整个项目期限内,每月,每周,每天要做的事情,作为组长的记录,多有不足之处,望指点。 转载于:https://www.cnblogs.com/mayijun/p/3458039.html

java.lang.OutOfMemoryError: PermGen space及其解决方法
PermGen space的全称是Permanent Generation space,是指内存的永久保存区域OutOfMemoryError: PermGen space从表面上看就是内存益出,解决方法也一定是加大内存。说说为什么会内存益出:这一部分用于存放Class和Meta的信息,Class在被 Load的时候被放入Per…

ceph-dencoder工具使用详解
文章目录简介使用decode命令用法encode简介 ceph-dencoder工具是一个序列化编码、解码并且打印ceph数据结构的工具。它主要用来调试和测试ceph不同版本之间的兼容性问题 该工具是由 ceph-common-12.2.1.06-0.el7.centos.x86_64 rpm包生成 本文章是根据ceph-12.2.1版本来描述改…

EBS fnd_global.apps_initialize
原型:fnd_global.apps_initialize(user_ID, Responsibility_id,Responsibility_application_id);作用:在数据库的会话中设置全局变量,和用户概要信息。参数获得:参数一,用户ID select user_idfrom fnd_userwhere user_…

js判断鼠标靠近屏幕最侧面的监听_threejs按鼠标位置缩放场景
threejs的orbitcontrol,默认的缩放模式为整体以target为中心进行缩放。有时候,我们想让场景按照鼠标位置进行缩放,体验起来就和地图的缩放一样,最直观的感觉就是整个场景会越来越靠近鼠标点的位置,而不是整体的缩放大小…

hibernate中多对多分解成一对多,
1,参考:http://blog.csdn.net/yaerfeng/article/details/6969632

C++ 函数参数 值传递与引用传递
以前我们在C语言中函数参数传递过程中,如果我们想要让当A函数作用域中的变量经过B函数处理之后的数值仍然在A函数中生效,这个时候函数参数的传递时需要引用方式去传递,方式如下: #include <stdio.h> //函数参数为指针&…

SharePoint 2013 图文开发系列之代码定义列表
在SharePoint的开发中,用Visual Studio自定义列表是经常会用到的,因为很多时候,我们并不会手动创建列表,而手动创建列表在测试服务器和正式机之间同步字段,也很麻烦,所以我们经常用代码来定义列表或者文档库…

arduino下载库出错_【arduino】DIY音乐播放器,arduino播放wav音乐,TRMpcm库测试及使用...
微信关注 “DLGG创客DIY”设为“星标”,重磅干货,第一时间送达。arduino特点库超多,想必大家都领教了,今天来分享一下之前玩过的TRMpcm库。这个库是干嘛用的?简单粗暴用arduino(这里特指arduino官方那几个板子uno、nan…

vim替换技巧4
、 转自:http://www.confay.com/2008/03/vim4.html [技巧一] 第一个是在VIM邮件列表中看到的,给出了一个如何统计文章字数的方法。 统计一个完整文件的字数,可以使用Unix下的wc工具,它能够统计一个文件的行数、单词数和字符数。 如…

spark1.x和2.xIterable和iterator兼容问题
1. spark 1.x 升级到spark 2.x 对于普通的spark来说,变动不大 : 1 举一个最简单的实例:spark1.x public static JavaRDD<String> workJob(JavaRDD<String> spark1Rdd) {JavaPairRDD<String, Integer> testRdd spark1Rdd.flatMapToPair(new PairFlatMapFunct…

C++ 拷贝构造函数和重载赋值运算符的区别
文章目录拷贝构造函数重载赋值运算符赋值运算符和拷贝构造函数最大区别是赋值运算符没有新的对象生成,而拷贝构造函数会生成新的对象。 为了更加形象 准确得描述 赋值运算符和拷贝构造函数得区别,将详细通过代码展示两者之间得差异。 拷贝构造函数 首先…

单元格内多个姓名拆分成一列_EXCEL拆分单元格中的姓名,这都不叫事儿
作者:祝洪忠 转自:Excel之家ExcelHome小伙伴们好啊,今天老祝和大家来分享一个数据整理的技巧。下面的表格形式,想必大家不会陌生吧:在这个表格内,同一个部门的人员名单都挤到一个单元格内。现在问题来了&am…
3.1 A Historical Perspective 历史观点
1.从1978年的8086到现在的2008年core i7 ,从29K个晶体管到781M个晶体管,地址线(也叫地址位长(bit long))8086只有20个地址线,1982年,MS-windows 使用80286平台开发了自己的windows。直到1985年,i386正式扩展…

idea中 maven打包时时报错User setting file does not exist C:\Users\lenevo\.m2\setting.xml,
第一种错误 :idea中 maven打包时时报错User setting file does not exist C:\Users\lenevo\.m2\setting.xml, 解决方案如下:将maven的安装目录\conf目录下的setting.xml拷贝到C:\Users\lenevo\.m2目录下即可。 第二种错误: This a…

关于部署osd过程中:Device is in use by a device-mapper mapping问题解决
ceph环境:12.2.1 使用古老的ceph-disk工具部署osd,仅仅prepare过程中就出现如上所示问题 Device is in use by a device-mapper mapping md127 解决方法如下: 由于device-mapper为系统自己的磁盘映射器,此时检查系统是否有逻辑卷 pvs lvs vg…

spyder一打开就卡了_欧姆龙plc 用 SD 卡上传/下载程序
以Nx102为例,NJ类似。使用 SD 卡将 Sysmac Studio 编写的程序传入 NX1P2 内; 使用 SD 卡对NX1P2 的程序进行备份, 查看备份的程序, 并把备份的程序传入另一台对应型号的 NX1P2 内。一、 使用 SD 卡将 Sysmac Studio 写的程序传入 …

Unity3D 中 2D_Toolkit插件下载 和 导入方法
Unity3D 中 2D_Toolkit插件下载 和 导入方法 1.你把下载来的包放到 安装目录:Editor\Standard Packages里面。 2.然后按ctrl9,进入asset store,等页面加载。 3.页面加载成功后,如果有账号,就登录,没有账号先…

Emacs 使用YASnippet
<?xml version"1.0" encoding"utf-8"?> Emacs 使用YASnippetUP | HOME Emacs 使用YASnippet Table of Contents 1 安装YASnippent2 安装 org-mode字典3 org-mode中使用教程4 YASnippet增加模板1 安装YASnippent $ cd ~/.emacs.d/plugins $ git c…

ruoyi后台管理系统分析(三)---admin包
三、admin包 --web包 -----controller包 -----------common包 CommonController.java------通用请求处理 package com.ruoyi.web.controller.common;import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import javax.servlet.http.HttpServletRequest;…

ceph-objectstore-tool工具使用详解
文章目录简介使用OSD相关操作PG相关操作对象相关操作总结简介 ceph-objectstore-tool工具,能够操作到ceph最底层的数据,包括pg,对象层级。它能够对底层pg以及对象相关数据进行获取、修改。并能够对一些问题pg和对象进行简单修复。所以使用该工具进行操作…

slf4j导入那个依赖_学习SPRINGBOOT结合日志门面SLF4J和日志实现LOGBACK的混合使用
一、此处主要介绍在springboot工程下如何使用 logback slf4j 进行日志记录。logback主要包含三个组成部分:Loggers(日志记录器)、Appenders(输出目的在)、Layouts(日志输出格式) slf4j :如jdbc一样,定义了一套接口,是一个日志门面…

linux下发布的执行文件崩溃的问题定位 心得一则
C Release版本发布到客户处执行时,如果程序崩溃,有什么办法能够快速的确认程序的问题呢? 如果能gdb调试的话,比较简单了,可以使用gdb命令,类似如下:gdb ##set args ****b mainr#eipx/10i 0xb736…

7 个漂亮的 JavaScript 的时间轴组件 [转]
时间轴:通过互联网技术,依据时间顺序,把一方面或多方面的 时间足迹事件串联起来,形成相对完整的记录体系,再运用图文的形式呈现给用户;时间轴可以运用于不同领域,最大的作用就是把过去的事物系统…