C++2.0新特性(八)——<Smart Pointer(智能指针)之unique_ptr>

一、概念介绍

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

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

1.1 出现的目的性

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

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

 1.2 unique_ptr的使用

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

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

 1 //自定义deleter
 2     class ClassDeleter
 3     {
 4     public:
 5         void operator()(std::string *p)
 6         {
 7             std::cout << "delete string object" << std::endl;
 8             delete p;
 9         }
10     };
11     
12 
13     std::unique_ptr<std::string, ClassDeleter> up(new std::string("hello"));

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

 

 1.9 unique_ptr使用举例

 1 #include <iostream>
 2 #include <string>
 3 #include <memory>    // for unique_ptr
 4 #include <dirent.h>  // for opendir(), ...
 5 #include <cstring>   // for strerror()
 6 #include <cerrno>    // for errno
 7 using namespace std;
 8 
 9 class DirCloser
10 {
11   public:
12     void operator () (DIR* dp) {
13         if (closedir(dp) != 0) {
14             std::cerr << "OOPS: closedir() failed" << std::endl;
15         }
16     }
17 };
18 
19 int main()
20 {
21     // open current directory:
22     unique_ptr<DIR,DirCloser> pDir(opendir("."));
23 
24     // process each directory entry:
25     struct dirent *dp;
26     while ((dp = readdir(pDir.get())) != nullptr) {
27         string filename(dp->d_name);
28         cout << "process " << filename << endl;
29         //...
30     }
31 }

  上例中使用了标准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关注的是最小量的空间开销和时间开销。

 

 

 

posted @ 2019-11-07 15:12  灼光  阅读(431)  评论(0编辑  收藏  举报
document.body.oncopy=function(){ event.returnValue=false; var t=document.selection.createRange().text; var curUrl = window.location.href; var s="本文来源于灼光的博客(https://www.cnblogs.com/laiyingpeng/) , 原文地址:" + curUrl + "转载请加上原文地址。"; clipboardData.setData('Text','\r\n'+t+'\r\n'+s+'\r\n\r\n\r\n'); }