一、概念介绍

  unique_ptr它是一种在异常发生时可帮助避免资源泄露的smart pointer,实现了独占式拥有的概念,意味着它可确保一个对象和其他相应资源在同一时间只被一个pointer拥有,一旦拥有者被销毁或变成空或开始拥有另一个对象,那么先前拥有的那个对象就会被销毁,其任何相应资源亦会被释放。

  Class unique_pt继承自class auto_ptr(由于不安全已被弃用),但它提供了更简明的接口,更不易出错。

1.1 出现的目的性

  为了避免异常时的资源泄露,通常函数会捕获所有的异常,例如:

上图中多个catch时会造成代码臃肿且累赘,使用unique_ptr能很好解决这个问题,改写如下:

1.2 unique_ptr的使用

  unique_ptr有着和寻常指针非常相似的接口,*操作符用来提取指向的对象,如果被指向的对象是class或struct,->操作符还可以用来访问成员,然而由于它是独占式的指针,所以不提供++算术符

 //必须直接初始化,不允许用赋值的语法将一个寻常的指针当作初值
//std::unique_ptr<std::string> = new int;//error
std::unique_ptr<std::string> up(new std::string("nico"));//OK
(*up)[] = 'X'; //替换第一个元素
(*up).append("lai");
std::cout <<(*up).data() << std::endl;
std::cout << up.get()<<std::endl;

  unique_ptr不必一定拥有对象,它也可以是empty,比如是被default构造函数创建出来的:

   也可以使用release放弃拥有权,并转移到另外一个上:

//必须直接初始化,不允许用赋值的语法将一个寻常的指针当作初值
//std::unique_ptr<std::string> = new int;//error
std::unique_ptr<std::string> up(new std::string("nico"));//OK
(*up)[] = 'X'; //替换第一个元素
(*up).append("lai");
std::cout <<(*up).data() << std::endl;
std::cout << up.get()<<std::endl;
auto str = up.release();
//release之后所有权就转移到str了,up就为NULL了
std::cout << str->data();

1.3 转移unique_ptr的拥有权

  unique_ptr提供的语义是“独占式拥有”,然而这个责任必须由我们使用者来确保“不可以使两个unique_ptr以同一个pointer作为初值”,如下:

std::string *sp = new std::string("hello");
std::unique_ptr<std::string> up1(sp);
std::unique_ptr<std::string> up2(sp);//错误,这是个运行期错误,

  27行第一个语句结束后,up1拥有以new创建的对象,第二个语句试图调用copy构造函数,但发生编译期错误,因为up2不可以成为原对象的另一个拥有者,毕竟一次只允许存在一个拥有者,第三个语句则是将拥有权从up1转移到up3,在那之前up3就拥有了先前new建立起来的对象,而up1不再拥有它,一旦up3被销毁,以new创建出来的对象也就被delete,失去拥有权的unique_ptr会变为空,如果要想指派新值,新值必须也是个unique_ptr,不可以是寻常的pointer

std::unique_ptr<std::string> ptr;
//ptr = new std::string; //error
ptr = std::unique_ptr<std::string>(new std::string("hello"));//OK 删除就对象,拥有新对象(delete old object and own new)
ptr = nullptr;//和调用reset差不多,如果有对象的话删除关联的所有对象( deletes the associated,if any)

1.4 转移权unique_ptr两种用途

  拥有权的转移指出了unique_ptr的一种用途:函数可以利用他们将拥有权转移给其他函数

  • (1)、函数是接收端

  如果我们将一个由std::move()建立起来的unique_ptr以rvalue reference身份当作函数实参,那么被调用函数的参数将会取得unique_ptr的拥有权,因此如果该函数不再转移拥有权,对象会在函数结束时被delete:

  • (2)、函数是供应端

  当函数返回一个unique_ptr,其拥有权会转移到调用端内:

  注意:千万不要声明返回类型为rvalue reference,因为那会返回一个dangling pointer(悬空指针)

1.5 unique_ptr被当作成员可避免资源泄露

1.6 unique_ptr对于array的使用

1.7 标准库unique_ptr的默认形式

1.8 自定义deleter

  当我们在unique_ptr结束时不再紧紧是调用delete或delete []时,我们就需要自定义deleter,然而此处的deleter定义方式不同于shared_ptr,你必须具体指明unique_ptr的类型的第二个模板参数,该类型可以时reference to function、function pointer或function object,如果是function object,其函数类型操作符()应该接受一个"指向对象"的pointer

 //自定义deleter
class ClassDeleter
{
public:
void operator()(std::string *p)
{
std::cout << "delete string object" << std::endl;
delete p;
}
}; std::unique_ptr<std::string, ClassDeleter> up(new std::string("hello"));

  如果给入的类型是个函数或lambda,你必须声明deletr的类型为void(*)(T*)或std::function<void(T*)>,要不就使用decltype

1.9 unique_ptr使用举例

 #include <iostream>
#include <string>
#include <memory> // for unique_ptr
#include <dirent.h> // for opendir(), ...
#include <cstring> // for strerror()
#include <cerrno> // for errno
using namespace std; class DirCloser
{
public:
void operator () (DIR* dp) {
if (closedir(dp) != ) {
std::cerr << "OOPS: closedir() failed" << std::endl;
}
}
}; int main()
{
// open current directory:
unique_ptr<DIR,DirCloser> pDir(opendir(".")); // process each directory entry:
struct dirent *dp;
while ((dp = readdir(pDir.get())) != nullptr) {
string filename(dp->d_name);
cout << "process " << filename << endl;
//...
}
}

  上例中使用了标准posix接口:opendir()、readdir()、closedir(),为了确保任何情况下被开启的目录都会被closedir()关闭,我们定义一个unique_ptr,造成只要”指向被开启目录“的那个handle被销毁,DirCloser就会被调用。

1.10 unique_ptr深究

  class unique_ptr提供了一个”带有独占拥有权的smart pointer语义“的概念,一旦某个unique pointer有了独占控制权,你将无法创造出”多个pointer拥有该相应对象“的形势,主要目的是确保在那个pointer寿命结束时,相应对象被删除(或是资源被清理干净),这特别有助于提供异常安全性,相比于shared pointer,这个class关注的是最小量的空间开销和时间开销。

C++2.0新特性(八)——<Smart Pointer(智能指针)之unique_ptr>的更多相关文章

  1. C++2.0新特性(六)——<Smart Pointer(智能指针)之shared_ptr>

    Smart Pointer(智能指针)指的是一类指针,并不是单一某一个指针,它能知道自己被引用的个数以至于在最后一个引用消失时销毁它指向的对象,本文主要介绍C++2.0提供的新东西 一.Smart P ...

  2. C++2.0新特性(七)——<Smart Pointer(智能指针)之weak_ptr>

    一.weak_ptr出现的意义 上一节提到过shared_ptr,它会自动释放“不再需要使用的对象”的相应的资源,但是它不是万能的,在某些时候(比如说循环引用),它会显得力不从心,这就是weak_pt ...

  3. 【C++11新特性】 C++11智能指针之weak_ptr

    如题,我们今天要讲的是C++11引入的三种智能指针中的最后一个:weak_ptr.在学习weak_ptr之前最好对shared_ptr有所了解.如果你还不知道shared_ptr是何物,可以看看我的另 ...

  4. [CareerCup] 13.8 Smart Pointer 智能指针

    13.8 Write a smart pointer class. A smart pointer is a data type, usually implemented with templates ...

  5. C++ smart pointer智能指针

      在C++中,程序员可以直接操作内存,给编程增加了不少的灵活性.但是灵活性是有代价的,程序员必须负责自己负责释放自己申请的内存,否则就会出现内存泄露.智能指针就是为了解决这个问题而存在的.它和其他指 ...

  6. Smart pointer 智能指针小总结

    Smart pointer line 58之后smart pointer里的计数已经是0,所以会真正释放它引用的对象,调用被引用对象的析构函数.如果继续用指针访问,会出现如下图的内存访问异常.所以说如 ...

  7. 【C++11新特性】 C++11智能指针之shared_ptr

    C++中的智能指针首先出现在“准”标准库boost中.随着使用的人越来越多,为了让开发人员更方便.更安全的使用动态内存,C++11也引入了智能指针来管理动态对象.在新标准中,主要提供了shared_p ...

  8. Smart Pointer 智能指针

    P76 参考:http://www.cnblogs.com/lanxuezaipiao/p/4132096.html http://blog.csdn.net/hackbuteer1/article/ ...

  9. [C#]6.0新特性浅谈

    原文:[C#]6.0新特性浅谈 C#6.0出来也有很长一段时间了,虽然新的特性和语法趋于稳定,但是对于大多数程序猿来说,想在工作中用上C#6.0估计还得等上不短的一段时间.所以现在再来聊一聊新版本带来 ...

随机推荐

  1. OpenFace 调试记录

    1.OpenFace 是 卡耐基梅陇(CMU)大学的一个图像+机器学习项目,整体程序包含:人脸发现,特征提取,特征神经网络训练,人脸识别这四部分. github   https://github.co ...

  2. AngularJS重型前端框架

    一.AngularJs AngularJs是一种前端的重型框架,而现在正在被Aue.js所取代.而Aue的和AngularJs大同小异. AngularJs核心功能有MVC.模块化.自动化双向数据绑定 ...

  3. 单词eschaunge交易所eschaunge交换

    Exchange of one person or thing for another; reciprocal giving and receiving: (a) of prisoners of wa ...

  4. 基于Text-CNN模型的中文文本分类实战

    Text-CNN 1.文本分类 转眼学生生涯就结束了,在家待就业期间正好有一段空闲期,可以对曾经感兴趣的一些知识点进行总结. 本文介绍NLP中文本分类任务中核心流程进行了系统的介绍,文末给出一个基于T ...

  5. Oracle间隔(interval)分区

    (一)什么是间隔分区 间隔分区是Oracle 11.1引入的新功能,通过该功能,可以在输入相应分区的数据时自动创建相应的分区.在没有间隔分区技术之前,DBA通常会创建一个maxvalue分区以避免OR ...

  6. 【Java字节码】Idea中查看Java字节码的插件jclasslib Bytecode viewer

    Idea插件搜索:jclasslib Bytecode viewer 安装完后,maven install你的项目(因为该插件会读取target下的class文件),然后选中某个java文件,按下图操 ...

  7. django项目中使用bootstrap插件的分页功能。

    官网下载bootstrap插件放到项目中的static文件中 路由 path('blog-fullwidth/', login.fullwidth,name='fullwidth'), 前端页面引入 ...

  8. Kotlin反射在属性上的应用实战

    继续研究Kotlin反射相关的东东,看代码: 接下来则遍历函数,来调一下,比如咱们先来调用一下带有2个参数的method方法,可以这样写: 其实在调用实例方法时的第一个参数永远都是要调用的那个实例,也 ...

  9. DT资讯文章生成静态出现MySQL Error解决办法

    今天有个朋友的DT系统生成静态出现 MySQL Query:SELECT * FROM [pre]article_21 WHERE status=3 and itemid<>516548 ...

  10. 2019-2020-1 20199301《Linux内核原理与分析》第八周作业

    第七章 可执行程序工作原理 ELF概述: 目标平台:它决定了编译器使用的机器命令集. ABI(目标文件) 目标文件和目标平台是二进制兼容的,即该目标文件已经是适应某一种CPU体系结构的二进制指令. E ...