unique_ptr 不共享它的指针。它无法复制到其他 unique_ptr,无法通过值传递到函数,也无法用于需要副本的任何标准模板库 (STL) 算法。只能移动unique_ptr。这意味着,内存资源所有权将转移到另一 unique_ptr,并且原始 unique_ptr 不再拥有此资源。我们建议你将对象限制为由一个所有者所有,因为多个所有权会使程序逻辑变得复杂。因此,当需要智能指针用于纯 C++ 对象时,可使用 unique_ptr,而当构造 unique_ptr 时,可使用make_unique Helper 函数。

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 实例之间的所有权转换。

1、如何创建unique_ptr

unique_ptr不像shared_ptr一样拥有标准库函数make_shared来创建一个shared_ptr实例。要想创建一个unique_ptr,我们需要将一个new 操作符返回的指针传递给unique_ptr的构造函数。

示例:

int main()
{// 创建一个unique_ptr实例unique_ptr<int> pInt(new int(5));cout << *pInt;
}

2、无法进行复制构造和赋值操作

unique_ptr没有copy构造函数,不支持普通的拷贝和赋值操作。

int main()
{// 创建一个unique_ptr实例unique_ptr<int> pInt(new int(5));unique_ptr<int> pInt2(pInt);    // 报错unique_ptr<int> pInt3 = pInt;   // 报错
}

3、可以进行移动构造和移动赋值操作

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));
}

4、可以返回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;
}

使用举例:{//创建一个指向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

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));// ...(可能会抛出异常)
}

2、返回函数内动态申请资源的所有权

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;// 函数结束后,自动释放资源
}

3、在容器中保存指针

int main()
{vector<unique_ptr<int>> vec;unique_ptr<int> p(new int(5));vec.push_back(std::move(p));    // 使用移动语义
}

4、管理动态数组

标准库提供了一个可以管理动态数组的unique_ptr版本。

int main()
{unique_ptr<int[]> p(new int[5] {1, 2, 3, 4, 5});p[0] = 0;   // 重载了operator[]
}

5、作为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::Foo
Foo::~Foo
Foo::Foo
Foo::Foo
Foo::Foo
Foo::Foo
Foo::~Foo
Foo::~Foo
Foo::~Foo
Foo::~Foo
Foo::Foo
D operator()
Foo::~Foo
TestOwner....................
Foo::Foo
Foo::bar
f(const Foo&)
Foo::bar
destroying p2...
Foo::bar
Foo::~Foo
TestArrayOwner....................
Foo::Foo
Foo::Foo
Foo::Foo
Foo::Foo
Foo::bar
f(const Foo&)
Foo::bar
destroying p2...
Foo::bar
Foo::~Foo
Foo::~Foo
Foo::~Foo
Foo::~Foo
 

« 上一篇: C++ 11 创建和使用 shared_ptr
» 下一篇: C++ 11 创建和使用共享 weak_ptr

C++11 unique_ptr用法相关推荐

  1. C++新特性探究(18.2):C++11 unique_ptr智能指针详解

    C++11 unique_ptr智能指针   作为智能指针的一种,unique_ptr 指针自然也具备"在适当时机自动释放堆内存空间"的能力.和shared_ptr指针最大的不同之 ...

  2. C++11智能指针shared_ptr、weak_ptr、unique_ptr用法

    该博文为原创文章,未经博主同意不得转载,如同意转载请注明博文出处 本文章博客地址:https://cplusplus.blog.csdn.net/article/details/105065859 智 ...

  3. C++11 function用法 可调用对象模板类

    std::function<datatype()> ()内写参数类型 datatype 代表function的返回值 灵活的用法.. 代码如下 1 #include <stdio.h ...

  4. c++新特性11 (11)unique_ptr

    有一个_Compressed_pair成员,类似于pair<key,value>队 // CLASS TEMPLATE unique_ptr SCALAR template <cla ...

  5. 数据库索引的作用和优点缺点以及索引的11中用法

    为什么要创建索引呢?这是因为,创建索引可以大大提高系统的性能.  第一,通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性.  第二,可以大大加快 数据的检索速度,这也是创建索引的最主要的原因. ...

  6. 数据库索引的作用和优点缺点以及索引的11种用法

    为什么要创建索引呢?这是因为,创建索引可以大大提高系统的性能. 第一,通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性. 第二,可以大大加快 数据的检索速度,这也是创建索引的最主要的原因. 第 ...

  7. C++11 unique_ptr智能指针详解

    文章目录 0.应用场景 1.初始化方式 2.常用操作 3.例子 例子1 创建unique_ptr并以引用形式传递给函数 例子2 用vector管理unique_ptr 例子3 unique_ptr作为 ...

  8. Python零碎知识(11):assert用法

    参考: http://www.cnblogs.com/herbert/archive/2013/01/12/2857233.html assert语句,如果没记错,这个东西在C或者C++里面也有的.属 ...

  9. C++11智能指针(unique_ptr、shared_ptr、weak_ptr)boost::scoped_ptr

    C++11智能指针(unique_ptr.shared_ptr.weak_ptr)_-码农小非-的专栏-CSDN博客_c++ shared_ptr weak_ptr 原创)智能指针拾遗 (原创)智能指 ...

最新文章

  1. C语言中的位运算和逻辑运算
  2. Chroot vsftpd with non-system users (ftp)
  3. 制作可以自动隐藏的弹出式菜单
  4. 病例对照研究和队列研究详解
  5. java中时间入数据库格式转换_数据库中字段类型为datetime,转换成java中的Date类型...
  6. 三十二楼层选几层最好_买房楼层怎么选?建筑学家建议:一栋楼不管几层,最好避开这3层...
  7. zookeeper客户端练习(idea-Junit测试)
  8. vmware安装ubuntu
  9. 阮一峰的学习Javascript闭包(Closure)
  10. 宝塔自助建站系统源码v8.0
  11. 东风本田4S店违规收取续保押金 ,电台主持在线怒怼经理,反被指无教养?
  12. VB 按指定编码格式写入文本文件
  13. NPDP产品经理认证:精益画布使用六步法
  14. Mesa核心数据结构
  15. idea快速创建包快捷键大全_idea快捷键大全
  16. 小码哥C++学院-零基础入门C语言
  17. 【P4lang】什么是P4?
  18. 移动 app安全评估检测技术分析
  19. photoshop入门笔记1:PS的快捷键
  20. 阿里巴巴2015校园招聘面试大礼包

热门文章

  1. 分析easyVM 未完成)
  2. 学习官方示例 - SysUtils.EncodeDate、EncodeTime、StrToDate、StrToTime、StrToDateTime
  3. Thinkphp 3.2.2 利用phpexcel完成excel导出功能
  4. 子域名查询DNS记录查询
  5. C# 系统应用之调用SDelete程序粉碎文件及基础原理知识
  6. HarmonyOS之深入解析视频的功能和使用
  7. 手把手教你Android Studio的安装与配置
  8. Python设计模式之外观模式实例讲解
  9. 一入爬虫深似海,反爬技术你知多少?
  10. 大数据WEB阶段(九)Servlet+Request