1. unique_ptr 是什么?
在 C++ 的世界里,内存管理一直是个让人头疼的问题。传统的手动 new/delete 方式不仅容易出错,还会导致内存泄漏和悬空指针等问题。unique_ptr 作为现代 C++(C++11 及以后版本)引入的智能指针之一,就是为了解决这些问题而生的。
unique_ptr 是一种独占所有权的智能指针,它确保在任何时候,只有一个 unique_ptr 实例可以指向特定的对象。当 unique_ptr 离开作用域时,它所管理的对象会被自动删除。这种设计模式完美体现了 RAII(Resource Acquisition Is Initialization)原则,即资源获取即初始化。
提示:RAII 是 C++ 的核心编程理念之一,它通过将资源(如内存、文件句柄等)的生命周期与对象的生命周期绑定,确保资源能够被正确释放。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. unique_ptr 的核心特性
2.1 独占所有权
unique_ptr 最显著的特点就是它的独占性。这意味着:
- 不能复制 unique_ptr(复制构造函数和复制赋值运算符被删除)
- 只能移动 unique_ptr(通过 std::move)
- 任何时候只有一个 unique_ptr 指向特定对象
这种设计避免了多个指针同时管理同一块内存的情况,从根本上杜绝了双重释放的问题。
2.2 自动内存管理
当 unique_ptr 离开作用域时,它会自动删除所管理的对象。这意味着你再也不需要手动调用 delete,减少了内存泄漏的风险。
cpp复制{
std::unique_ptr<int> ptr(new int(42));
// 使用 ptr
} // 这里 ptr 离开作用域,int 对象被自动删除
2.3 自定义删除器
unique_ptr 允许你指定自定义的删除器,这在管理非内存资源时特别有用。例如,管理文件句柄:
cpp复制struct FileDeleter {
void operator()(FILE* fp) const {
if (fp) fclose(fp);
}
};
std::unique_ptr<FILE, FileDeleter> filePtr(fopen("data.txt", "r"));
3. unique_ptr 的基本用法
3.1 创建 unique_ptr
创建 unique_ptr 有几种常见方式:
cpp复制// 方式1:直接构造
std::unique_ptr<int> ptr1(new int(10));
// 方式2:使用 std::make_unique (C++14 引入)
auto ptr2 = std::make_unique<int>(20);
// 方式3:管理数组
auto ptr3 = std::make_unique<int[]>(10); // 管理包含10个int的数组
注意:推荐使用 std::make_unique 而不是直接 new,因为它更安全(防止内存泄漏)且更高效(减少一次内存分配)。
3.2 转移所有权
由于 unique_ptr 不能复制,只能移动,转移所有权需要使用 std::move:
cpp复制auto ptr1 = std::make_unique<int>(42);
// auto ptr2 = ptr1; // 错误!不能复制
auto ptr2 = std::move(ptr1); // 正确,转移所有权
// 现在 ptr1 为空,ptr2 拥有对象
3.3 访问对象
可以通过 operator* 和 operator-> 访问 unique_ptr 管理的对象:
cpp复制auto ptr = std::make_unique<std::string>("Hello");
std::cout << *ptr << std::endl; // 解引用
std::cout << ptr->size() << std::endl; // 成员访问
4. unique_ptr 的高级用法
4.1 作为函数参数和返回值
unique_ptr 非常适合作为函数参数和返回值,因为它明确表达了所有权的转移:
cpp复制std::unique_ptr<Resource> createResource() {
return std::make_unique<Resource>();
}
void processResource(std::unique_ptr<Resource> res) {
// 处理资源
}
auto res = createResource(); // 所有权从函数转移到调用者
processResource(std::move(res)); // 所有权转移到函数
4.2 与多态类型一起使用
unique_ptr 可以很好地处理多态类型:
cpp复制class Base {
public:
virtual ~Base(
