C++11智能指针中的 unique_ptr实例详解

在前面一篇文章中,我们了解了 C++11 中引入的智能指针之一 shared_ptr 和 weak_ptr ,今天,我们来介绍一下另一种智能指针 unique_ptr 。

往期文章参考:

【C++11新特性】 C++11 智能指针之shared_ptr

【C++11新特性】 C++11智能指针之weak_ptr

unique_ptr介绍

unique是独特的、唯一的意思,故名思议,unique_ptr可以“独占”地拥有它所指向的对象,它提供一种严格意义上的所有权。

这一点和我们前面介绍的 shared_ptr 类型指针有很大的不同:shared_ptr 允许多个指针指向同一对象,而 unique_ptr 在某一时刻只能有一个指针指向该对象。

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

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[]
}

总结

到此这篇关于C++11智能指针中的 unique_ptr实例详解的文章就介绍到这了,更多相关C++11智能指针unique_ptr内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

时间: 2020-06-08

C++11智能指针之weak_ptr详解

如题,我们今天要讲的是 C++11 引入的三种智能指针中的:weak_ptr. 在学习 weak_ptr 之前最好对 shared_ptr 有所了解.如果你还不知道 shared_ptr 是何物,可以看看另一篇文章: [C++11新特性] C++11智能指针之shared_ptr 1.为什么需要weak_ptr? 在正式介绍weak_ptr之前,我们先来回忆一下shared_ptr的一些知识. 我们知道shared_ptr是采用引用计数的智能指针,多个shared_ptr实例可以指向同一个动态对

c++11&14-智能指针要点汇总

学c++的人都知道,在c++里面有一个痛点,就是动态内存的管理,就我所经历的一些问题来看,很多莫名其妙的问题,最后都发现是内存管理不当引起的. 但像java等其他一些语言则不会有这样的问题,为什么呢,因为它们有很好的处理内存的方法,比如java的垃圾回收机制,现在,我们c++终于也有了智能指针. 1. 什么是智能指针 简单地说,智能指针是用对象去管理一个资源指针,同时用一个计数器计算引用当前指针对象的个数,当管理指针的对象增加或减少时,计数器也相应加1或减1,当最后一个指针管理对象销毁时,计数器

C++11新特性之智能指针(shared_ptr/unique_ptr/weak_ptr)

shared_ptr基本用法 shared_ptr采用引用计数的方式管理所指向的对象.当有一个新的shared_ptr指向同一个对象时(复制shared_ptr等),引用计数加1.当shared_ptr离开作用域时,引用计数减1.当引用计数为0时,释放所管理的内存. 这样做的好处在于解放了程序员手动释放内存的压力.之前,为了处理程序中的异常情况,往往需要将指针手动封装到类中,通过析构函数来释放动态分配的内存:现在这一过程就可以交给shared_ptr去做了. 一般我们使用make_shared来

C++11 智能指针之shared_ptr代码详解

C++中的智能指针首先出现在"准"标准库boost中. 随着使用的人越来越多,为了让开发人员更方便.更安全的使用动态内存,C++11也引入了智能指针来管理动态对象. 在新标准中,主要提供了shared_ptr.unique_ptr.weak_ptr三种不同类型的智能指针. 接下来的几篇文章,我们就来总结一下这些智能指针的使用. 今天,我们先来看看shared_ptr智能指针. shared_ptr 智能指针 shared_ptr是一个引用计数智能指针,用于共享对象的所有权也就是说它允许

智能指针与弱引用详解

在android 中可以广泛看到的template<typename T> class Sp 句柄类实际上是android 为实现垃圾回收机制的智能指针.智能指针是c++ 中的一个概念,因为c++ 本身不具备垃圾回收机制,而且指针也不具备构造函数和析构函数,所以为了实现内存( 动态存储区) 的安全回收,必须对指针进行一层封装,而这个封装就是智能指针,其实说白了,智能指针就是具备指针功能同时提供安全内存回收的一个类.当然,智能指针的功能还不只这些,想了解更多大家可以去研究下- 智能指针有很多实现

C++11 std::shared_ptr总结与使用示例代码详解

最近看代码,智能指针用的比较多,自己平时用的少,周末自己总结总结.方便后续使用. std::shared_ptr大概总结有以下几点: (1) 智能指针主要的用途就是方便资源的管理,自动释放没有指针引用的资源. (2) 使用引用计数来标识是否有多余指针指向该资源.(注意,shart_ptr本身指针会占1个引用) (3) 在赋值操作中, 原来资源的引用计数会减一,新指向的资源引用计数会加一. std::shared_ptr<Test> p1(new Test); std::shared_ptr&l

C语言中的指针以及二级指针代码详解

很多初学者都对C中的指针很迷糊,希望这篇blog能帮助到大家: 1.什么是"指针": 在执行C程序的时候,由于我们的数据是存储在内存中的.所以对于C程序本身来说,如果想找到相应被调用的数据,就要知道存储该数据的内存地址是多少,换言之,C程序通过已知的内存地址到相应的内存位置存储数据. 这里简单说一下内存管理(对于初学者来说.为了避免专业术语引发的理解问题,下面的叙述尽量避免专业定义:),对于现代计算机系统来说,内存空间分为两个区域,一个是"数据区",一个是"

C#集合类用法实例代码详解

下面介绍C#的集合类 1ArrayList using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Collections; namespace 动态数组ArrayList { class Program { static void Main(string[] args) { ArrayList

MySQL主库binlog(master-log)与从库relay-log关系代码详解

主库binlog: # at 2420 #170809 17:16:20 server id 1882073306 end_log_pos 2451 CRC32 0x58f2db87 Xid = 32880 COMMIT/*!*/; # at 2451 #170814 11:07:18 server id 1882073306 end_log_pos 2528 CRC32 0x40774a4b Query thread_id=92 exec_time=0 error_code=0 SET TIM

Java回调函数实例代码详解

首先说说什么叫回调函数? 在WINDOWS中,程序员想让系统DLL调用自己编写的一个方法,于是利用DLL当中回调函数(CALLBACK)的接口来编写程序,使它调用,这个就 称为回调.在调用接口时,需要严格的按照定义的参数和方法调用,并且需要处理函数的异步,否则会导致程序的崩溃. 这样的解释似乎还是比较难懂,这里举个简 单的例子: 程序员A写了一段程序(程序a),其中预留有回调函数接口,并封装好了该程序.程序员B要让a调用自己的程序b中的一个方法,于是,他通过a中的接口回调自己b中的方法.目的达到

springboot扫描自定义的servlet和filter代码详解

这几天使用spring boot编写公司一个应用,在编写了一个filter,用于指定编码的filter,如下: /** * Created by xiaxuan on 16/11/1. */ @WebFilter(urlPatterns = "/*",filterName="CharacterEncodeFilter", initParams={ @WebInitParam(name="encoding",value="UTF-8&qu