随着 C++11 标准的引入,智能指针成为了现代 C++ 编程中资源管理的核心工具。其中,unique_ptr
是一种独占式的智能指针,负责管理动态分配的对象,确保在不再需要时自动释放内存,避免内存泄漏。本文将全面、准确地介绍 unique_ptr
的用法、特点以及在实际编程中的应用和注意事项。
一、什么是 unique_ptr
unique_ptr
是 C++11 标准库中的智能指针,位于头文件 <memory>
中。它实现了独占式所有权,即同一时间内只有一个 unique_ptr
指向某个动态分配的对象。当 unique_ptr
被销毁时,所管理的对象也会被自动销毁,避免了内存泄漏。
特点:
- 独占所有权:
unique_ptr
独自拥有所指向的对象,不能复制或共享。 - 移动语义支持:支持移动构造和移动赋值,可以转移所有权。
- 轻量级:无需引用计数,开销较小。
二、unique_ptr
的基本用法
2.1 初始化 unique_ptr
方法一:直接使用构造函数
|
|
方法二:使用 std::make_unique
(C++14 引入)
|
|
方法三:从已有的原始指针初始化(不推荐)
|
|
注意: 方法三存在风险,如果多个 unique_ptr
管理同一原始指针,会导致未定义行为。
2.2 使用 unique_ptr
-
访问所管理的对象
1 2 3
std::unique_ptr<AA> ptr = std::make_unique<AA>("对象名称"); ptr->成员函数(); (*ptr).成员函数();
-
禁止复制和赋值
1 2 3
std::unique_ptr<int> p1(new int(10)); std::unique_ptr<int> p2 = p1; // 错误,不能复制 p2 = p1; // 错误,不能赋值
-
移动所有权
1
std::unique_ptr<int> p3 = std::move(p1); // p1 资源转移给 p3
2.3 函数参数中的 unique_ptr
-
传递所有权
如果函数需要接管
unique_ptr
的所有权,可以通过 移动语义 传递:1 2 3 4
void func(std::unique_ptr<AA> ptr) { // 接管所有权 } func(std::move(p1));
-
共享访问
如果函数只需要访问对象,不需要所有权,可以传递 引用 或 原始指针:
1 2
void func(const std::unique_ptr<AA>& ptr); // 传引用 void func(const AA* ptr); // 传原始指针
三、unique_ptr
的高级特性
3.1 所有权转移与移动语义
unique_ptr
禁止复制构造和复制赋值,但支持移动构造和移动赋值。这意味着可以通过 std::move
转移所有权。
|
|
注意: 转移所有权后,原来的 unique_ptr
将不再指向对象,应避免再次使用。
3.2 自定义删除器
unique_ptr
支持自定义删除器,以替代默认的 delete
操作。
|
|
3.3 管理动态数组
unique_ptr
提供了针对数组的特化版本,可以管理动态分配的数组。
|
|
注意: 管理数组时,unique_ptr
会使用 delete[]
来释放内存。
四、unique_ptr
的成员函数与操作
-
operator*
和operator->
1 2
*ptr; // 解引用,访问对象 ptr->func(); // 通过指针访问成员函数
-
get()
返回所管理对象的原始指针。
1
AA* raw_ptr = ptr.get();
-
release()
释放所有权,返回原始指针,
unique_ptr
置为空。1
AA* raw_ptr = ptr.release(); // 需要手动 delete raw_ptr
-
reset()
重置
unique_ptr
,释放当前对象并接管新对象。1 2
ptr.reset(new AA("新对象")); ptr.reset(); // 释放对象,置为空
-
swap()
交换两个
unique_ptr
所管理的对象。1
ptr1.swap(ptr2);
五、示例代码解析
5.1 示例一:unique_ptr
在函数中的使用
|
|
运行结果:
|
|
解析:
- 使用
make_unique
创建一个unique_ptr
,指向对象 “西施”。 - 调用
func4
,通过move
转移所有权,pu
被置空。 - 函数结束后,
func4
内的unique_ptr
被销毁,自动调用析构函数。
5.2 示例二:使用 unique_ptr
管理数组
|
|
运行结果:
|
|
解析:
- 创建一个
unique_ptr<AA[]>
,管理一个大小为 2 的AA
数组。 - 通过下标操作赋值和访问数组元素。
- 程序结束时,
unique_ptr
自动调用delete[]
释放内存。
六、注意事项与最佳实践
-
禁止复制操作
unique_ptr
禁止复制构造和复制赋值,确保独占所有权。 -
慎用原始指针初始化
避免使用同一个原始指针初始化多个
unique_ptr
,会导致多次释放同一内存。 -
不要管理非动态分配的内存
unique_ptr
应该只管理通过new
分配的内存,不要用于栈内存或其他方式分配的内存。 -
转移所有权时使用
std::move
当需要将
unique_ptr
作为函数参数并转移所有权时,使用std::move
。 -
管理数组时使用特化版本
使用
unique_ptr<T[]>
来管理动态数组,支持下标操作符。 -
自定义删除器
如果需要自定义资源释放方式,可以在
unique_ptr
中指定自定义删除器。 -
避免空悬指针
当
unique_ptr
被销毁或转移所有权后,应避免再次使用。
七、总结
unique_ptr
是现代 C++ 中管理动态内存的首选工具之一。通过独占式的所有权模型和对移动语义的支持,unique_ptr
提供了高效、安全的资源管理方式。在实际编程中,合理使用 unique_ptr
,可以显著减少内存泄漏和空悬指针等问题,提高代码的可靠性和可维护性。