首页 > C++智能指针:unique_ptr详解

C++智能指针:unique_ptr详解

文章目录

      • unique_ptr描述
        • 声明
        • 作用
      • 函数指针描述
      • 总结

unique_ptr描述

声明

头文件:

模版类:

  • 默认类型template > class unique_ptr
  • 数组类型template class unique_ptr;

作用

与shared_ptr最大的区别即是unique_ptr不能够共享同一个地址,它对地址是独占得。当unique_ptr对象的生命周期结束,则它所引用的地址空间也会被释放。

一个unique_ptr对象主要包含两个部分

  • 一个存储指针:主要用来管理对象的地址空间。它是在构造函数中分配的地址,并且能够通过赋值运算符以及reset成员函数进行地址空间的重新指向。并且可以通过get和release成员变量进行单独访问,获取unique_ptr对象的地址空间。
  • 一个存储删除器:删除器为一个可以被调用的对象。主要被用来删除unique_ptr对象的地址空间。同时能够使用赋值运算符进行当前对象的更改,并通过get_deleter成员函数进行单独访问。

函数指针描述

  • 构造函数
    //unique_ptr constructor example
    #include 
    #include 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") << '
    ';std::cout << "u2: " << (u2?"not null":"null") << '
    ';std::cout << "u3: " << (u3?"not null":"null") << '
    ';std::cout << "u4: " << (u4?"not null":"null") << '
    ';std::cout << "u5: " << (u5?"not null":"null") << '
    ';std::cout << "u6: " << (u6?"not null":"null") << '
    ';std::cout << "u7: " << (u7?"not null":"null") << '
    ';std::cout << "u8: " << (u8?"not null":"null") << '
    ';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 
    #include int main () { auto deleter = [](int*p){ delete p;std::cout << "[deleter called]
    ";};std::unique_ptr<int,decltype(deleter)> foo (new int,deleter);std::cout << "foo " << (foo?"is not":"is") << " empty
    ";return 0;                        // [deleter called]
    }
    
    输出如下:
    foo is not empty
    [deleter called]
    
  • operator=
    // unique_ptr::operator= example
    #include 
    #include 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 << '
    '; else std::cout << "empty
    ";std::cout << "bar: ";if (bar) std::cout << *bar << '
    '; else std::cout << "empty
    ";return 0;
    }
    
    输出如下:
    foo: empty
    bar: 101
    
  • std :: unique_ptr :: get成员,改成员函数返回被管理的unique_ptr对象,此函数的调用不会使unique_ptr释放指针的所有权(即,它仍然负责在某个时刻删除管理数据)。因此,此函数返回的值不得用于构造新的管理指针。为了活动存储指针,并且能够正常释放,则使用release()成员函数
    // unique_ptr::get vs unique_ptr::release
    #include 
    #include 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 << '
    '; else std::cout << "(null)
    ";std::cout << "bar: ";if (bar) std::cout << *bar << '
    '; else std::cout << "(null)
    ";std::cout << "p: ";if (p) std::cout << *p << '
    '; else std::cout << "(null)
    ";std::cout << '
    ';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 
    #include 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 << '
    ';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 
    #include 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() << '
    ';*up=5;std::cout << *up << " " << up.get() << '
    ';up.reset (new int);       // deletes managed object, acquires new pointer*up=10;std::cout << *up << " " << up.get() << '
    ';up.reset();               // deletes managed objectreturn 0;
    }
    
    输出如下:
    0 0xd7dc70
    5 0xd7dc70
    10 0xd7dc90
    
  • std::unique_ptr::swap交换对象空间以及内容,且并不破坏地址空间
    // unique_ptr::swap example#include #include int main () { std::unique_ptr<int> foo (new int(10));std::unique_ptr<int> bar (new int(20));std::cout << "foo: " << *foo << " " << foo.get() << '
    ';std::cout << "bar: " << *bar << " " << bar.get() << '
    ';foo.swap(bar);std::cout << "foo: " << *foo << " " << foo.get() << '
    ';std::cout << "bar: " << *bar << " " << bar.get() << '
    ';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

更多相关:

  • 经过长期探索,发现一个不需要手动设置线程休眠时间(e.g. std::this_thread::sleep_for(std::chrono::microseconds(1)))的代码: Github: https://github.com/log4cplus/ThreadPool #ifndef THREAD_POOL_H_7e...

  • nth_element(first,nth,last) first,last 第一个和最后一个迭代器,也可以直接用数组的位置。  nth,要定位的第nn 个元素,能对它进行随机访问. 将第n_thn_th 元素放到它该放的位置上,左边元素都小于它,右边元素都大于它. 测试代码: http://www.cplusplus.com...

  • c/c++老版本的rand()存在一定的问题,在转换rand随机数的范围,类型或者分布时,常常会引入非随机性。 定义在 中的随机数库通过一组协作类来解决这类问题:随机数引擎 和 随机数分布类 一个给定的随机数发生器一直会生成相同的随机数序列。一个函数如果定义了局部的随机数发生器,应该将(引擎和分布对象)定义为 st...

  • jsoncpp 是一个C++ 语言实现的json库,非常方便得支持C++得各种数据类型到json 以及 json到各种数据类型的转化。 一个json 类型的数据如下: {"code" : 10.01,"files" : "","msg" : "","uploadid" : "UP000000" } 这种数据类型方便我们人阅读以...

  • 问题如下: 已知一组数(其中有重复元素),求这组数可以组成的所有子集中,子 集中的各个元素和为整数target的子集,结果中无重复的子集。 例如: nums[] = [10, 1, 2, 7, 6, 1, 5], target = 8 结果为: [[1, 7], [1, 2, 5], [2, 6], [1, 1, 6]] 同样之前有...

  • C++11标准中可以为模板定义别名,比如 template using ptr=std::shared_ptr; //这里模板定义ptr为智能指针std::shared_ptr定义的别名 所以实际应用中可以借此来简化代码,比如 #include #include

  • 先说结论,智能指针都是非线程安全的。 多线程调度智能指针 这里案例使用的是shared_ptr,其他的unique_ptr或者weak_ptr的结果都是类似的,如下多线程调度代码: #include #include #include #include #i...

  • 文章目录unique_ptr 智能指针的实现shared_ptr 智能指针的实现指针类型转换 unique_ptr 智能指针的实现 一个对象只能被单个unique_ptr 所拥有。 #include using namespace std;/*增加模板类型,保证智能指针的类型是由传入的类型决定的*/ t...

  • 文章目录weak_ptr描述声明作用原理实现函数成员使用总结 weak_ptr描述 声明 头文件: 模版类:template class weak_ptr 声明方式:std::weak_ptr statement 作用 根据boost库的官方描述,weak_ptr是...

  • 文章目录shared_ptr描述声明作用原理实现函数使用关于shared_ptr循环引用问题 shared_ptr描述 声明 shared_ptr属于C++11特性中新加的一种智能指针,它的实现方式是模版类,头文件 template class shared_ptr 所以使用shared...