参考:

  1. https://www.cnblogs.com/DswCnblog/p/5628195.html
  2. https://www.jianshu.com/p/3abef7d9a5ee
  3. https://blog.csdn.net/luoshabugui/article/details/86130728

std::unique_ptr 是 C++11 起引入的智能指针。为什么必须要在 C++11 起才有该特性,主要还是 C++11 增加了move语义,否则无法对对象的所有权进行传递。

1. unique_ptr 介绍

  • unique_ptr 不共享它的指针。它无法复制到其他 unique_ptr,无法通过值传递到函数,也无法用于需要副本的任何标准模板库 (STL) 算法。只能移动unique_ptr。这意味着,内存资源所有权将转移到另一 unique_ptr,并且原始 unique_ptr 不再拥有此资源。我们建议你将对象限制为由一个所有者所有,因为多个所有权会使程序逻辑变得复杂。因此,当需要智能指针用于纯 C++ 对象时,可使用 unique_ptr,而当构造 unique_ptr 时,可使用make_unique 函数。
  • std::unique_ptr 实现了独享所有权的语义。一个非空的 std::unique_ptr 总是拥有它所指向的资源。转移一个 std::unique_ptr 将会把所有权也从源指针转移给目标指针(源指针被置空)。拷贝一个 std::unique_ptr 将不被允许,因为如果你拷贝一个 std::unique_ptr ,那么拷贝结束后,这两个 std::unique_ptr 都会指向相同的资源,它们都认为自己拥有这块资源(所以都会企图释放)。因此 std::unique_ptr 是一个仅能移动(move_only)的类型。当指针析构时,它所拥有的资源也被销毁。默认情况下,资源的析构是伴随着调用 std::unique_ptr 内部的原始指针的 delete 操作的。
  • 下图演示了两个 unique_ptr 实例之间的所有权转换:

2. 创建unique_ptr

  • unique_ptr 不像 shared_ptr 一样拥有标准库函数 make_shared 来创建一个 shared_ptr 实例。要想创建一个 unique_ptr,我们需要将一个new 操作符返回的指针传递给 unique_ptr 的构造函数。
  • std::make_unique 是 C++14 才有的特性。
// 示例:
int main()
{// 创建一个unique_ptr实例unique_ptr<int> pInt(new int(5));cout << *pInt;
}

3. 无法进行复制构造和赋值操作

  • unique_ptr 没有copy构造函数,不支持普通的拷贝和赋值操作。
// 示例:
int main()
{// 创建一个unique_ptr实例unique_ptr<int> pInt(new int(5));unique_ptr<int> pInt2(pInt);    // 报错unique_ptr<int> pInt3 = pInt;   // 报错
}

4. 可以进行移动构造和移动赋值操作

  • unique_ptr 虽然没有支持普通的拷贝和赋值操作,但却提供了一种移动机制来将指针的所有权从一个 unique_ptr 转移给另一个 unique_ptr 。如果需要转移所有权,可以使用std::move()函数。
// 示例:
int main()
{unique_ptr<int> pInt(new int(5));unique_ptr<int> pInt2 = std::move(pInt);    // 转移所有权//cout << *pInt << endl; // 出错,pInt为空cout << *pInt2 << endl;unique_ptr<int> pInt3(std::move(pInt2));
}

5. 可以返回unique_ptr

  • unique_ptr不支持拷贝操作,但却有一个例外:可以从函数中返回一个unique_ptr。
// 示例:
unique_ptr<int> clone(int p)
{unique_ptr<int> pInt(new int(p));return pInt;    // 返回unique_ptr
}int main() {int p = 5;unique_ptr<int> ret = clone(p);cout << *ret << endl;
}

6. unique_ptr使用示例

{//创建一个指向int的空指针std::unique_ptr<int> fPtr1;std::unique_ptr<int> fPtr2(new int(4));auto fPtr3 = std::make_unique<int>();//fPtr2释放指向对象的所有权,并且被置为nullptrstd::cout << "fPtr2 release before:" << fPtr2.get() << std::endl;int *pF = fPtr2.release();std::cout << "fPtr2 release before:" << fPtr2.get() << " and pF value:" << *pF << std::endl;//所有权转移,转移后fPtr3变为空指针std::cout << "move before fPtr1 address:" << fPtr1.get() << " fPtr3 address:" << fPtr3.get() << std::endl;fPtr1 = std::move(fPtr3);std::cout << "move after fPtr1 address:" << fPtr1.get() << " fPtr3 address:" << fPtr3.get() << std::endl;std::cout << "move before fPtr1 address:" << fPtr1.get() << std::endl;fPtr1.reset();std::cout << "move after fPtr1 address:" << fPtr1.get() << std::endl;
}
# 输出:fPtr2 release before:00EFB120fPtr2 release before:00000000 and pF value:4move before fPtr1 address:00000000 fPtr3 address:00EFEC60move after fPtr1 address:00EFEC60 fPtr3 address:00000000move before fPtr1 address:00EFEC60move after fPtr1 address:00000000

7. unique_ptr使用场景

  1. 为动态申请的资源提供异常安全保证:
    我们先来看看下面这一段代码:
void Func()
{int *p = new int(5);// ...(可能会抛出异常)delete p;
}

这是我们传统的写法:当我们动态申请内存后,有可能我们接下来的代码由于抛出异常或者提前退出(if语句)而没有执行delete操作。

解决的方法是使用 unique_ptr 来管理动态内存,只要 unique_ptr 指针创建成功,其析构函数都会被调用,确保动态资源被释放。

void Func()
{unique_ptr<int> p(new int(5));
}
  1. 返回函数内动态申请资源的所有权:
unique_ptr<int> Func(int p)
{unique_ptr<int> pInt(new int(p));return pInt;    // 返回unique_ptr
}int main() {int p = 5;unique_ptr<int> ret = Func(p);cout << *ret << endl;// 函数结束后,自动释放资源
}
  1. 在容器中保存指针:
int main()
{vector<unique_ptr<int>> vec;unique_ptr<int> p(new int(5));vec.push_back(std::move(p));    // 使用移动语义
}
  1. 管理动态数组:
    标准库提供了一个可以管理动态数组的 unique_ptr 版本。
int main()
{unique_ptr<int[]> p(new int[5] {1, 2, 3, 4, 5});p[0] = 0;   // 重载了operator[]
}
  1. 作为auto_ptr的替代品:
    创建与释放举例:
#include <iostream>
#include <memory>
#include <stdlib.h>struct Foo
{Foo() { std::cout << "Foo::Foo\n"; }~Foo() { std::cout << "Foo::~Foo\n"; }void bar() { std::cout << "Foo::bar\n"; }
};void f(const Foo &)
{std::cout << "f(const Foo&)\n";
}struct D
{void operator()(Foo* foo){std::cout << "D operator()" << std::endl;delete foo;}
};void TestAutoDestroy()
{//1. 普通的new对象.std::cout << "TestDestroy...................." << std::endl;{std::unique_ptr<Foo> p1(new Foo);}//2. 普通的new[]对象.{std::unique_ptr<Foo[]> p2(new Foo[4]);}//3. 自定义的deleter.{std::unique_ptr<Foo, D> p3(new Foo);}
}void TestOwner()
{std::cout << "TestOwner...................." << std::endl;//1. new object.std::unique_ptr<Foo> p1(new Foo);  // p1 owns Fooif (p1) p1->bar();{std::unique_ptr<Foo> p2(std::move(p1));  // now p2 owns Foof(*p2);p1 = std::move(p2);  // ownership returns to p1p2->bar();std::cout << "destroying p2...\n";}p1->bar();
}void TestArrayOwner()
{std::cout << "TestArrayOwner...................." << std::endl;//1. new[] object.std::unique_ptr<Foo[]> p1(new Foo[4]);  // p1 owns Fooif (p1) p1[0].bar();{std::unique_ptr<Foo[]> p2(std::move(p1));  // now p2 owns Foof(p2[0]);p1 = std::move(p2);  // ownership returns to p1p2[0].bar();std::cout << "destroying p2...\n";}p1[0].bar();
}int main()
{TestAutoDestroy();TestOwner();TestArrayOwner();
}
# 输出:TestDestroy....................Foo::FooFoo::~FooFoo::FooFoo::FooFoo::FooFoo::FooFoo::~FooFoo::~FooFoo::~FooFoo::~FooFoo::FooD operator()Foo::~FooTestOwner....................Foo::FooFoo::barf(const Foo&)Foo::bardestroying p2...Foo::barFoo::~FooTestArrayOwner....................Foo::FooFoo::FooFoo::FooFoo::FooFoo::barf(const Foo&)Foo::bardestroying p2...Foo::barFoo::~FooFoo::~FooFoo::~FooFoo::~Foo

8. 总结

  1. unique_ptr独占管理对象,只有移动语义。
  2. unique_ptr可以不占用对象,即为空。可以通过reset()或者赋值nullptr释放管理对象。
  3. 标准库早期版本中定了auto_ptr,它具有unique_ptr的部分特征,但不是全部。例如不能在容器中保存auto_ptr,不能从函数中返回auto_ptr等等,这也是unique_ptr主要的使用场景。

【C++11】 之 std::unique_ptr 详解相关推荐

  1. C++11 并发指南三(std::mutex 详解)

    上一篇<C++11 并发指南二(std::thread 详解)>中主要讲到了 std::thread 的一些用法,并给出了两个小例子,本文将介绍 std::mutex 的用法. Mutex ...

  2. 【转】C++11 并发指南五(std::condition_variable 详解)

    http://www.cnblogs.com/haippy/p/3252041.html 前面三讲<C++11 并发指南二(std::thread 详解)>,<C++11 并发指南三 ...

  3. C++11 并发指南五(std::condition_variable 详解)

    前面三讲<C++11 并发指南二(std::thread 详解)>,<C++11 并发指南三(std::mutex 详解)>分别介绍了 std::thread,std::mut ...

  4. C++11 并发指南------std::thread 详解

    参考: https://github.com/forhappy/Cplusplus-Concurrency-In-Practice/blob/master/zh/chapter3-Thread/Int ...

  5. 智能指针 unique_ptr 详解

    一.智能指针 1.什么是智能指针 简单地说,C++智能指针是包含重载运算符的类,其行为像常规指针,但智能指针能够及时.妥善地销毁动态分配的数据,并实现了明确的对象生命周期,因此更有价值. 2.常规指针 ...

  6. c++ std::move详解

    c++ std::move详解 在移动构造中的时候,移动拷贝其实就是把原来参数对象的指针地址给到了构造的对象,再把原先对象的指针置为NULL,这样内存就不会被原来函数给析构了.对于实体的对象执行的其实 ...

  7. python的shutil模块是内置的_Python之shutil模块11个常用函数详解,python内置函数是什么...

    Python之shutil模块11个常用函数详解,python内置函数是什么 shutil 是 Python 中的高级文件操作模块,与os模块形成互补的关系,os主要提供了文件或文件夹的新建.删除.查 ...

  8. kubernetes系列11—PV和PVC详解

    kubernetes系列11-PV和PVC详解 原文:kubernetes系列11-PV和PVC详解 本文收录在容器技术学习系列文章总目录 1.认识PV/PVC/StorageClass 1.1 介绍 ...

  9. Linux-0.11 文件系统bitmap.c详解

    Linux-0.11 文件系统bitmap.c详解 模块简介 该模块包含了两对函数,第一对是和i节点相关的free_inode()和new_inode().第二对是和逻辑块相关的free_block( ...

最新文章

  1. Nginx学习之二-配置项解析及编程实现
  2. 2020科目一考试口诀_科目一考试口诀,看完少练超多题,需要轻松备考的学员请收藏!...
  3. Coursera课程Python for everyone:chapter7
  4. 理解分布式系统中的缓存架构(上)
  5. 哪些深度相机有python接口_python 从深度相机realsense生成pcl点云
  6. 时间自适应卷积:比自注意力更快的特征提取器
  7. == 捕获对象时的模式切换 ==
  8. SAP UI5 的控件Focus 相关处理逻辑
  9. Python 实现 csv文件转换成json文件
  10. 传感器的特性及性能参数
  11. 和pbs的区别_少女针Ellanse易丽适和童颜针的区别,最全面解析
  12. 【转载】一个通过JSONP跨域调用WCF REST服务的例子(以jQuery为例)
  13. vip会员统计表 (vip等级是灵活配置的 非写死1是金卡用户 2是什么 等)
  14. 计算机启动dos,开机怎么进入dos_开机怎么进入dos界面
  15. 从零开始学习CANoe(三)—— 系统变量的创建和使用
  16. ASTC on Android
  17. 智能家居linux 源码,搭建开源智能家居系统Domoticz
  18. Bluetooth LMP介绍
  19. java c语言 关系_java和c语言有什么共同点?
  20. 厦门大学计算机学院考研报录人数,院校情报局 | 厦门大学近5年报考人数及录取人数大汇总!...

热门文章

  1. 公司申请高新认定需要有多少个软件著作权证书?
  2. 简单快速清理 联想电脑 顽固可疑程序文件 comup.dll(风险名称: Adware/Hyideo )的方法 PS:该方法对于删除 .dll 文件均有效
  3. 没错,我们和美帝的差距就是这么大!
  4. 【C】报错[Error] lvalue required as left operand of assignment
  5. 计算机四级网络工程师 郑州报考条件,郑州市网络工程师证在哪报名、考试费用...
  6. 机票预定系统可行性分析
  7. 监测数据处理系统-自动导出监测日报表、周报表及月报表(基坑监测、地铁监测)
  8. 计算机数值模拟仿真技术的优点,数值模拟的优缺点优点.ppt
  9. 软碟通(UltraISO注册码) v9.5.3.2901汉化版
  10. Go The Way 之切片