c++11 智能指针 (std::unique_ptr)(一)
定义于头文件 <memory>
template<class T,class Deleter = std::default_delete<T>>
class unique_ptr; (1) (C++11 起) template <class T, class Deleter>
class unique_ptr<T[], Deleter>; (2) (C++11 起)
std::unique_ptr
是通过指针占有并管理另一对象,并在 unique_ptr
离开作用域时释放该对象的智能指针。
在下列两者之一发生时用关联的删除器释放对象:
- 销毁了管理的
unique_ptr
对象 - 通过 operator= 或 reset() 赋值另一指针给管理的
unique_ptr
对象。
通过调用 get_deleter()(ptr) ,用潜在为用户提供的删除器释放对象。默认删除器用 delete 运算符,它销毁对象并解分配内存。
unique_ptr
亦可以不占有对象,该情况下称它为空 (empty)。
std::unique_ptr
有两个版本:
1) 管理单个对象(例如以 new 分配)
2) 管理动态分配的对象数组(例如以 new[] 分配)
类满足可移动构造 (MoveConstructible) 和可移动赋值 (MoveAssignable) 的要求,但不满足可复制构造 (CopyConstructible) 或可复制赋值 (CopyAssignable) 的要求。
类型要求 | ||
- Deleter 必须是函数对象 (FunctionObject) 或到函数对象 (FunctionObject) 的左值引用或到函数的左值引用,可以 unique_ptr<T, Deleter>::pointer 类型参数调用
|
注意
只有非 const 的 unique_ptr
能转移被管理对象的所有权给另一 unique_ptr
。若对象的生存期为 const std::unique_ptr 所管理,则它被限定在创建指针的作用域中。
std::unique_ptr
常用于管理对象的生存期,包含:
- 通过正常退出和经由异常退出两者上的受保证删除,提供异常安全,给处理拥有动态生存期的对象的类和函数
- 传递独占的拥有动态生存期的对象的所有权到函数
- 从函数获得独占的拥有动态生存期对象的所有权
- 作为具移动容器的元素类型,例如保有指向动态分配对象的指针的 std::vector (例如,若想要多态行为)
std::unique_ptr
可为不完整类型 T
构造,例如用于改善用作 pImpl 手法中把柄的用途。若使用默认删除器,则 T
必须在代码中调用删除器点处完整,这发生于析构函数、移动赋值运算符和 std::unique_ptr
的 reset
成员函数中。(相反地, std::shared_ptr 不能从指向不完整类型的裸指针构造,但可于 T
不完整处销毁)。注意若 T
是类模板特化,则以 unique_ptr
为运算数的使用,如 !p ,因 ADL 而要求 T
的形参完整。
若 T
是某基类 B
的导出类,则 std::unique_ptr<T> 可隐式转换为 std::unique_ptr<B>。产生的 std::unique_ptr<B> 的默认删除器将使用 B
的 operator delete ,这导致未定义行为,除非 B
的析构函数为虚。注意 std::shared_ptr 表现有别: std::shared_ptr<B> 将使用类型 T
的 operator delete ,而且即使 B
的析构函数非虚,也会正确删除被占有对象。
不同于 std::shared_ptr , std::unique_ptr
可通过任何满足可空指针 (NullablePointer) 的定制把柄类型管理对象。例如,这允许管理位于共享内存,但提供定义 typedef boost::offset_ptr pointer;
或其他缀饰指针的 Deleter
的对象。
构造函数
初等模板 unique_ptr<T> 的成员
constexpr unique_ptr() noexcept;
constexpr unique_ptr( nullptr_t ) noexcept; (1) explicit unique_ptr( pointer p ) noexcept; (2) unique_ptr( pointer p, /* see below */ d1 ) noexcept; (3) unique_ptr( pointer p, /* see below */ d2 ) noexcept; (4) unique_ptr( unique_ptr&& u ) noexcept; (5) template< class U, class E >
unique_ptr( unique_ptr<U, E>&& u ) noexcept; (6) template< class U >
unique_ptr( std::auto_ptr<U>&& u ) noexcept; (7) (C++17 中移除)
数组特化 unique_ptr<T[]> 的成员
constexpr unique_ptr() noexcept;
constexpr unique_ptr( nullptr_t ) noexcept; (1) explicit unique_ptr( pointer p ) noexcept; (2) (C++17 前) template<class U> explicit unique_ptr( U p ) noexcept; (2) (C++17 起) unique_ptr( pointer p, /* see below */ d1 ) noexcept; (3) (C++17 前) template<class U> unique_ptr( U p, /* see below */ d1 ) noexcept; (3) (C++17 起) unique_ptr( pointer p, /* see below */ d2 ) noexcept; (4) (C++17 前) template<class U> unique_ptr( U p, /* see below */ d2 ) noexcept;(4) (C++17 起) unique_ptr( unique_ptr&& u ) noexcept; (5) template< class U, class E >
unique_ptr( unique_ptr<U, E>&& u ) noexcept; (6) (C++17 起)
1) 构造不占有对象的 std::unique_ptr
。值初始化存储的指针和存储的删除器。要求 Deleter
可默认构造 (DefaultConstructible) 且构造不抛异常。
若 |
(C++17 前) |
这些重载仅若 std::is_default_constructible<Deleter>::value 为 true 且 Deleter 不是指针类型才参与重载决议。 |
(C++17 起) |
2) 构造占有 p 的 std::unique_ptr
,以 p 初始化存储的指针,并值初始化存储的删除器。要求 Deleter
可默认构造 (DefaultConstructible) 且构造不抛异常。
若 |
(C++17 前) |
此重载仅若 std::is_default_constructible<Deleter>::value 为 true 且 Deleter 不是指针类型才参与重载决议。若类模板实参推导选择此构造函数,则程序为病式。 |
(C++17 起) |
3-4) 构造占有 p
的 std::unique_ptr
对象,以 p
初始化存储的指针,并按下列方式初始化删除器 D
(依赖于 D
是否为引用类型)
a) 若 D
是非引用类型 A ,则签名是:
unique_ptr(pointer p, const A& d) noexcept; |
(1) |
(要求 Deleter 为不抛出可复制构造 (CopyConstructible) )
|
unique_ptr(pointer p, A&& d) noexcept; |
(2) |
(要求 Deleter 为不抛出可移动构造 (MoveConstructible) )
|
b) 若 D
是左值引用类型 A& ,则签名是:
unique_ptr(pointer p, A& d) noexcept; |
(1) | |
unique_ptr(pointer p, A&& d); |
(2) |
c) 若 D
是左值引用类型 const A& ,则签名是:
unique_ptr(pointer p, const A& d) noexcept; |
(1) | |
unique_ptr(pointer p, const A&& d); |
(2) |
所有情况中删除器从 std::forward<decltype(d)>(d) 初始化。
若 |
(C++17 前) |
若 |
(C++17 起) |
2-4) 数组特化中表现同初等模板中接收一个指针参数的构造函数,除了它们不另外参与重载决议,除非下列之一为真:
|
(C++17 起) |
5) 通过从 u
转移所有权给 *this 构造 unique_ptr
并存储空指针于 u
。此构造函数仅若 std::is_move_constructible<Deleter>::value 为 true 才参与重载决议。若 Deleter
不是引用类型,则要求它为不抛出可移动构造 (MoveConstructible) (若 Deleter
是引用,则 get_deleter()
和 u.get_deleter()
在移动构造后引用相同值)。
6) 通过从 u
转移所有权给 *this 构造 unique_ptr
,其中 u
以指定的删除器( E
)构造。它依赖于 E
是否引用类型,如下:
a) 若 E
是引用类型,则从 u
的删除器复制构造此删除器(要求此构造不抛出)
b) 若 E
不是引用类型,则从 u
的删除器移动构造此删除器(要求此构造不抛出)
此构造函数仅若下列皆为真才参与重载决议:
a) unique_ptr<U, E>::pointer 可隐式转换为 pointer
b) U 不是数组类型
c) Deleter
是引用类型且 E
与 D
为同一类型,或 Deleter
不是引用类型且 E
可隐式转换为 D
6) 数组的特化中,表现同在初等模板中者,除了它仅若下列皆为真才会参与重载决议
|
(C++17 起) |
7) 构造 unique_ptr
,其中以 u.release()
初始化存储的指针,并值初始化存储的删除器。此构造函数仅若 U*
可隐式转换为 T*
且 Deleter
与 std::default_delete<T>
为同一类型才参与重载决议。
参数
p | - | 指向要管理的对象的指针 |
d1,d2 | - | 用于销毁对象的删除器 |
u | - | 获取所有权来源的智能指针 |
注意
使用 std::make_unique<T> 是更好的做法,可取代与 new 一起的重载 (2) 。
std::unique_ptr<Derived> 通过重载 (6) 可隐式转换为 std::unique_ptr<Base> (因为被管理指针和 std::default_delete 都可隐式转换)。
因为默认构造函数是 constexpr
,故静态的 unique_ptr 作为静态非局部初始化的一部分初始化,在任何动态初始化之前。这使得在任何静态对象的构造函数中使用 unique_ptr 是安全的。
无源自指针类型的类模板实参推导,因为不可能辨别来自 |
(C++17 起) |
调用示例
#include <iostream>
#include <memory>struct Foo // 要管理的对象
{Foo(){std::cout << "Foo ctor\n";}Foo(const Foo&){std::cout << "Foo copy ctor\n";}Foo(Foo&&){std::cout << "Foo move ctor\n";}~Foo(){std::cout << "~Foo dtor\n";}
};struct D // 删除器
{D() {};D(const D&){std::cout << "D copy ctor\n";}D(D&){std::cout << "D non-const copy ctor\n";}D(D&&){std::cout << "D move ctor \n";}void operator()(Foo* p) const{std::cout << "D is deleting a Foo\n";delete p;};
};int main()
{std::cout << "Example constructor(1)...\n";std::unique_ptr<Foo> up1; // up1 为空std::unique_ptr<Foo> up1b(nullptr); // up1b 为空std::cout << "Example constructor(2)...\n";{std::unique_ptr<Foo> up2(new Foo); // up2 现在占有 Foo} // Foo 被删除std::cout << "Example constructor(3)...\n";D d;{// 删除器类型不是引用std::unique_ptr<Foo, D> up3(new Foo, d); // 复制删除器}{// 删除器类型是引用std::unique_ptr<Foo, D&> up3b(new Foo, d); // up3b 保有到 d 的引用}std::cout << "Example constructor(4)...\n";{// 删除器不是引用std::unique_ptr<Foo, D> up4(new Foo, D()); // 移动删除器}std::cout << "Example constructor(5)...\n";{std::unique_ptr<Foo> up5a(new Foo);std::unique_ptr<Foo> up5b(std::move(up5a)); // 所有权转移}std::cout << "Example constructor(6)...\n";{std::unique_ptr<Foo, D> up6a(new Foo, d); // 复制 Dstd::unique_ptr<Foo, D> up6b(std::move(up6a)); // 移动 Dstd::unique_ptr<Foo, D&> up6c(new Foo, d); // D 是引用std::unique_ptr<Foo, D> up6d(std::move(up6c)); // 复制 D}std::cout << "Example constructor(7)...\n";{std::auto_ptr<Foo> up7a(new Foo);std::unique_ptr<Foo> up7b(std::move(up7a)); // 所有权转移}std::cout << "Example array constructor...\n";{std::unique_ptr<Foo[]> up(new Foo[3]);} // 删除三个 Foo 对象
}
输出
c++11 智能指针 (std::unique_ptr)(一)相关推荐
- 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 原创)智能指针拾遗 (原创)智能指 ...
- 【C++11新特性】 C++11智能指针之unique_ptr
原创作品,转载请标明:http://blog.csdn.net/Xiejingfa/article/details/50759210 在前面一篇文章中,我们了解了C++11中引入的智能指针之一shar ...
- webRTC之智能指针std::unique_ptr::reset()使用(十四)
一.std::unique_ptr::reset()使用 void reset (pointer p = pointer()) noexcept; 1.src/modules/audio_device ...
- C++自学24:唯一智能指针(make_unique/unique_ptr/reset/release/get/13.1)
使用make_unique获取一个智能指针,智能指针的类型是unique_ptr // a不是数组,小括号里的就是值 std::unique_ptr<int> a = std::make_ ...
- c++11 智能指针 (std::unique_ptr)(六)
定义于头文件 <memory> template< class T, class Deleter = std::default_delete<T>>class un ...
- C++11新特性——智能指针之unique_ptr
此课件及源代码来自B站up主:码农论坛,该文章仅作为本人学习笔记使用. unique_ptr独享它指向的对象,也就是说,同时只有一个unique_ptr指向同一个对象,当这个unique_ptr被销毁 ...
- 深入学习c++--智能指针(三) unique_ptr
1. 几种智能指针 1. auto_ptr: c++11中推荐不使用他(放弃) 2. shared_ptr: 拥有共享对象所有权语义的智能指针 3. unique_ptr: 拥有独有对象所有权语义的智 ...
- 详解C++11智能指针
详解C++11智能指针 前言 C++里面的四个智能指针: auto_ptr, unique_ptr,shared_ptr, weak_ptr 其中后三个是C++11支持,并且第一个已经被C++11弃用 ...
- 智能指针(unique_ptr、shared_ptr、weak_ptr)
主要参考链接:C++ 智能指针最佳实践&源码分析 参考链接:C++11 make_shared - 简书 智能指针在 C++11 标准中被引入真正的标准库(C++98 中引入的 auto_pt ...
- C++11 智能指针之shared_ptr
0.Overview 在实际的 C++ 开发中,我们经常会遇到诸如程序运行中突然崩溃.程序运行所用内存越来越多最终不得不重启等问题,这些问题往往都是内存资源管理不当造成的.比如: 有些内存资源已经被释 ...
最新文章
- C# 二种方法控制系统音量/麦克风大小
- 面试中你必须要知道的语言陷阱
- 聊聊storm的LoggingMetricsConsumer
- linux下一个apache+tomcat负载均衡和集群
- matlab 时序数据,9 个 MATLAB 数据科学速查表 - MATLAB Simulink
- java gzipoutputstream_java – GZIPInputStream逐行读取
- 【idea配置】电脑死机重启后idea报错cannot load project:com.intellij.ide
- Java 算法 素数对猜想
- python输出用逗号隔开的数字_Python:从字符串中提取带有点和逗号的数字
- 单线程reactor
- 国网英语计算机职称考试技巧,计算机职称考试通关的三大技巧
- 直播app开发必备五步流程
- Python爬虫课--第二节 爬虫请求模块 urllib.request,urllib.parse,requests模块
- 高一的我曾对自己说要放慢脚步去生活!?
- 二十一世纪大学英语读写教程(第三册)学习笔记(原文)——5 - America Seen with European Eyes(概说美国——欧洲人眼中的美国)
- AX200网卡支持linux,Intel 9260/AX200网卡在Deepin/UOS/Ubuntu下网速慢的处理
- win10 无法识别x64dbg 插件
- 微生物多样性数据分析(16S)
- 神器啊,理工男的春天来了!
- 《炬丰科技-半导体工艺》--技术资料合集三