在《C++11 shared_ptr智能指针》的基础上,本节继续讲解 C++11 标准提供的另一种智能指针,即 unique_ptr 智能指针。



作为智能指针的一种,unique_ptr 指针自然也具备“在适当时机自动释放堆内存空间”的能力。和 shared_ptr
指针最大的不同之处在于,unique_ptr 指针指向的堆内存无法同其它 unique_ptr 共享,也就是说,每个 unique_ptr
指针都独自拥有对其所指堆内存空间的所有权。

这也就意味着,每个 unique_ptr 指针指向的堆内存空间的引用计数,都只能为 1,一旦该 unique_ptr 指针放弃对所指堆内存空间的所有权,则该空间会被立即释放回收。

unique_ptr 智能指针是以模板类的形式提供的,unique_ptr<T>(T 为指针所指数据的类型)定义在<memory>头文件,并位于 std 命名空间中。因此,要想使用 unique_ptr 类型指针,程序中应首先包含如下 2 条语句:

  1. #include <memory>
  2. using namespace std;

第 2 句并不是必须的,可以不添加,则后续在使用 unique_ptr 指针时,必须标注std::

unique_ptr智能指针的创建

考虑到不同实际场景的需要,unique_ptr<T> 模板类提供了多个实用的构造函数,这里给读者列举了几种常用的构造 unique_ptr 智能指针的方式。



1) 通过以下  2 种方式,可以创建出空的 unique_ptr 指针:

  1. std::unique_ptr<int> p1();
  2. std::unique_ptr<int> p2(nullptr);

2) 创建 unique_ptr 指针的同时,也可以明确其指向。例如:

  1. std::unique_ptr<int> p3(new int);

由此就创建出了一个 p3 智能指针,其指向的是可容纳 1 个整数的堆存储空间。

和可以用 make_shared<T>() 模板函数初始化 shared_ptr 指针不同,C++11 标准中并没有为 unique_ptr 类型指针添加类似的模板函数。

3) 基于 unique_ptr 类型指针不共享各自拥有的堆内存,因此 C++11 标准中的 unique_ptr 模板类没有提供拷贝构造函数,只提供了移动构造函数。例如:

  1. std::unique_ptr<int> p4(new int);
  2. std::unique_ptr<int> p5(p4);//错误,堆内存不共享
  3. std::unique_ptr<int> p5(std::move(p4));//正确,调用移动构造函数

值得一提的是,对于调用移动构造函数的 p4 和 p5 来说,p5 将获取 p4 所指堆空间的所有权,而 p4 将变成空指针(nullptr)。



4) 默认情况下,unique_ptr 指针采用 std::default_delete<T>
方法释放堆内存。当然,我们也可以自定义符合实际场景的释放规则。值得一提的是,和 shared_ptr 指针不同,为 unique_ptr
自定义释放规则,只能采用函数对象的方式。例如:

  1. //自定义的释放规则
  2. struct myDel
  3. {
  4. void operator()(int *p) {
  5. delete p;
  6. }
  7. };
  8. std::unique_ptr<int, myDel> p6(new int);
  9. //std::unique_ptr<int, myDel> p6(new int, myDel());

unique_ptr<T>模板类提供的成员方法

为了方便用户使用 unique_ptr 智能指针,unique_ptr<T> 模板类还提供有一些实用的成员方法,它们各自的功能如表 1 所示。

表 1 unique_ptr指针可调用的成员函数
成员函数名 功 能
operator*() 获取当前 unique_ptr 指针指向的数据。
operator->() 重载 -> 号,当智能指针指向的数据类型为自定义的结构体时,通过 -> 运算符可以获取其内部的指定成员。
operator =() 重载了 = 赋值号,从而可以将 nullptr 或者一个右值 unique_ptr 指针直接赋值给当前同类型的 unique_ptr 指针。
operator []() 重载了 [] 运算符,当 unique_ptr 指针指向一个数组时,可以直接通过 [] 获取指定下标位置处的数据。
get() 获取当前 unique_ptr 指针内部包含的普通指针。
get_deleter() 获取当前 unique_ptr 指针释放堆内存空间所用的规则。
operator bool() unique_ptr 指针可直接作为 if 语句的判断条件,以判断该指针是否为空,如果为空,则为 false;反之为 true。
release() 释放当前 unique_ptr 指针对所指堆内存的所有权,但该存储空间并不会被销毁。
reset(p) 其中 p 表示一个普通指针,如果 p 为 nullptr,则当前 unique_ptr 也变成空指针;反之,则该函数会释放当前 unique_ptr 指针指向的堆内存(如果有),然后获取 p 所指堆内存的所有权(p 为 nullptr)。
swap(x) 交换当前 unique_ptr 指针和同类型的 x 指针。

除此之外,C++11标准还支持同类型的 unique_ptr 指针之间,以及 unique_ptr 和 nullptr 之间,做 ==,!=,<,<=,>,>= 运算。

下面程序给大家演示了 unique_ptr 智能指针的基本用法,以及该模板类提供了一些成员方法的用法:

  1. #include <iostream>
  2. #include <memory>
  3. using namespace std;
  4. int main()
  5. {
  6. std::unique_ptr<int> p5(new int);
  7. *p5 = 10;
  8. // p 接收 p5 释放的堆内存
  9. int * p = p5.release();
  10. cout << *p << endl;
  11. //判断 p5 是否为空指针
  12. if (p5) {
  13. cout << "p5 is not nullptr" << endl;
  14. }
  15. else {
  16. cout << "p5 is nullptr" << endl;
  17. }
  18. std::unique_ptr<int> p6;
  19. //p6 获取 p 的所有权
  20. p6.reset(p);
  21. cout << *p6 << endl;;
  22. return 0;
  23. }

程序执行结果为:

10

p5 is nullptr

10

------------------------------ 上面有误-------------

std::unique_ptr::release

pointer release() noexcept;
Release pointer

Releases ownership of its stored pointer, by returning its value and replacing it with a null pointer.



This call does not destroy the managed object, but the unique_ptr
object is released from the responsibility of deleting the object. Some
other entity must take responsibility for deleting the object at some
point.



To force the destruction of the object pointed, either use member function reset or perform an assignment operation on it.

Parameters

none

Return value

A pointer to the object managed by unique_ptr before the call.

pointer is a member type, defined as the pointer type that points to the type of object managed.

Example

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// unique_ptr::release example
#include <iostream>
#include <memory> int main () {
std::unique_ptr<int> auto_pointer (new int);
int * manual_pointer; *auto_pointer=10; manual_pointer = auto_pointer.release();
// (auto_pointer is now empty) std::cout << "manual_pointer points to " << *manual_pointer << '\n'; delete manual_pointer; return 0;
}

Output:

manual_pointer points to 10

See also

unique_ptr::reset
Reset pointer (public member function
)
unique_ptr::get
Get pointer (public member function
)
unique_ptr::operator=
unique_ptr assignment (public member function
)

C++11 unique_ptr智能指针详解的更多相关文章

  1. [转]C++ 智能指针详解

    转自:http://blog.csdn.net/xt_xiaotian/article/details/5714477 C++ 智能指针详解 一.简介 由于 C++ 语言没有自动内存回收机制,程序员每 ...

  2. C++ 智能指针详解(转)

    C++ 智能指针详解   一.简介 由于 C++ 语言没有自动内存回收机制,程序员每次 new 出来的内存都要手动 delete.程序员忘记 delete,流程太复杂,最终导致没有 delete,异常 ...

  3. 【C++】智能指针详解(一):智能指针的引入

    智能指针是C++中一种利用RAII机制(后面解释),通过对象来管理指针的一种方式. 在C++中,动态开辟的内存需要我们自己去维护,在出函数作用域或程序异常退出之前,我们必须手动释放掉它,否则的话就会引 ...

  4. [C++11新特性] 智能指针详解

    动态内存的使用很容易出问题,因为确保在正确的时间释放内存是极为困难的.有时我们会忘记释放内存产生内存泄漏,有时提前释放了内存,再使用指针去引用内存就会报错. 为了更容易(同时也更安全)地使用动态内存, ...

  5. 【C++】智能指针详解

    转自:https://blog.csdn.net/flowing_wind/article/details/81301001 参考资料:<C++ Primer中文版 第五版>我们知道除了静 ...

  6. C++智能指针详解

    本文出自http://mxdxm.iteye.com/ 一.简介 由于 C++ 语言没有自动内存回收机制,程序员每次 new 出来的内存都要手动 delete.程序员忘记 delete,流程太复杂,最 ...

  7. 【转】C++ 智能指针详解

    一.简介 由于 C++ 语言没有自动内存回收机制,程序员每次 new 出来的内存都要手动 delete.程序员忘记 delete,流程太复杂,最终导致没有 delete,异常导致程序过早退出,没有执行 ...

  8. 【C++】智能指针详解(二):auto_ptr

    首先,我要声明auto_ptr是一个坑!auto_ptr是一个坑!auto_ptr是一个坑!重要的事情说三遍!!! 通过上文,我们知道智能指针通过对象去管理指针,在构造对象时完成资源的分配及初始化,在 ...

  9. c++11之智能指针

    在c++98中,智能指针通过一个模板“auto_ptr”来实现,auto_ptr以对象的方式来管理堆分配的内存,在适当的时间(比如析构),释放所获得的内存.这种内存管理的方式只需要程序员将new操作返 ...

随机推荐

  1. python 10篇 操作mysql

    一.操作数据库 使用pip install pymysql,安装pymysql模块,使用此模块连接MySQL数据库并操作数据库. import pymysql host = 'ip地址' # 链接的主 ...

  2. PYTHON 当前.PY文件名不能与引入的模块同名

    当前文件名:sqlite3.py 文件引入import sqlite3 运行会出错,因为调用sqlite3的方法首先从当前文件找方法,当然找不到,所以会报错了

  3. [006] - JavaSE面试题(六):泛型

    第一期:Java面试 - 100题,梳理各大网站优秀面试题.大家可以跟着我一起来刷刷Java理论知识 [006] - JavaSE面试题(六):泛型 第1问:什么是泛型? Java泛型( generi ...

  4. java并发编程基础—生命周期与线程控制

    一.线程生命周期 线程被创建启动以后,他既不是一启动就进入执行状态,也不是一直处于执行状态,在线程的生命周期中,它要经过新建(New).就绪(Runnable).运行(Running).阻塞(Bloc ...

  5. springboot-5-持久层技术

    整合mybatis 流程: 导入依赖: 除了mybaits还有mysql和jdbc依赖 <!--mybatis--> <dependency> <groupId>o ...

  6. dubbo(四)

    前言 1.浅谈架构的发展 首先,要了解dubbo,就得了解,它是在什么背景下产生的?这就需要从架构的发展说起. 孟老师从事软件开发2008年份,那时候我上高一,那个时候,淘宝.京东都还没有火起来.那个 ...

  7. 深入刨析tomcat 之---第13篇 tomcat的三种部署方法

    writedby 张艳涛 一般我们都知道将web 应用打成war包,放到tomcat的webapp目录下,就是部署了,这是部署方法1 第2种部署方法我们也知道,就是讲web应用的文件夹拷贝到webap ...

  8. Android技术分享| 实现视频连麦直播

    视频连麦产品端核心步骤分析 游客申请连麦/取消申请 主播同意/拒绝申请 音视频发布取消 支持很多观众观看 支持多人连麦 低延时 IM 弹幕 视频连麦技术端调研 emmm,大致可以分为视频采集.编码,传 ...

  9. Java流程控制01——用户交互Scanner

    用户交互Scanner sacnner对象 之前的语法并没有实现程序与人的交互.java.util.Scanner是Java5的新特征,我们可以通过Scanner类来获取用户的输入. 基本语法:  S ...

  10. C语言复习(六)----typedef 的作用

    typedef的作用 重命名变量:typedef unsigned int Uint;//可以使用Uint代替unsigned int 定义新的数据类型 typedef struct Books{ c ...