跳到主要内容
版本:1.0

unique_ptr

std::unique_ptr 是 C++11 引入的智能指针类型,用于管理动态分配的对象。它的核心特点是:独占所有权,不能被复制,只能被移动。

它通过 RAII(资源获取即初始化)机制在对象生命周期结束时自动释放资源,能显著减少 new / delete 手动管理导致的内存泄漏风险。

头文件与基本特征

使用 unique_ptr 时,通常包含:

#include <memory>

主要特征:

特征说明
所有权模型独占所有权(同一时刻只有一个 unique_ptr 拥有对象)
拷贝语义禁止拷贝
移动语义支持移动(std::move
释放时机指针析构时自动释放
自定义删除器支持

基本用法

推荐使用 std::make_unique(C++14 起可用)创建对象:

#include <iostream>
#include <memory>

int main() {
std::unique_ptr<int> p = std::make_unique<int>(42);
std::cout << *p << '\n';
return 0;
}

如果你严格处于 C++11 环境,没有 make_unique,可临时写成:

std::unique_ptr<int> p(new int(42));

交互演示(MDX + React)

下面这个交互面板用于演示 moveresetrelease 的状态变化。它不是执行真实 C++ 代码,而是可视化 unique_ptr 所有权规则。

std::unique_ptr 所有权演示

通过点击按钮观察 move / reset / release 的状态变化。

MDX + React
ptrAResource#1
ptrBnullptr
released rawnone

ptrA 拥有对象

最近操作

  • 初始化: ptrA -> Resource#1

不能拷贝,只能移动

unique_ptr 不允许拷贝:

std::unique_ptr<int> p1(new int(10));
// std::unique_ptr<int> p2 = p1; // 编译错误

如果要转移所有权,必须移动:

#include <memory>

int main() {
std::unique_ptr<int> p1(new int(10));
std::unique_ptr<int> p2 = std::move(p1);

// 现在 p1 == nullptr, p2 拥有对象
return 0;
}

移动后,源指针通常变为空指针,应先判断再解引用。

常用成员函数

函数作用
get()获取裸指针(不转移所有权)
release()放弃所有权并返回裸指针(需要手动释放)
reset(ptr)释放当前对象并接管新对象
reset()释放当前对象并置空
swap(other)与另一个 unique_ptr 交换所有权
operator* / operator->像普通指针一样访问对象
operator bool判断是否为空

get()

get() 只借出裸指针,不改变所有权:

std::unique_ptr<int> p(new int(5));
int* raw = p.get();

raw 不能被 delete,因为资源仍由 p 管理。

release()

release() 会交出所有权:

std::unique_ptr<int> p(new int(5));
int* raw = p.release();

// p 变为空,raw 需要手动 delete
delete raw;

reset()

reset() 用于替换或清空托管对象:

std::unique_ptr<int> p(new int(5));
p.reset(new int(9)); // 先释放 5,再接管 9
p.reset(); // 释放 9 并置空

作为函数参数与返回值

作为参数(转移所有权)

#include <memory>

void consume(std::unique_ptr<int> p) {
// p 在函数结束时自动释放
}

int main() {
std::unique_ptr<int> p(new int(7));
consume(std::move(p));
return 0;
}

作为返回值

#include <memory>

std::unique_ptr<int> createValue() {
return std::unique_ptr<int>(new int(99));
}

int main() {
std::unique_ptr<int> p = createValue();
return 0;
}

返回 unique_ptr 是工厂函数的常见写法,表达“创建者把所有权交给调用者”。

管理数组

unique_ptr 可以管理动态数组:

#include <memory>

int main() {
std::unique_ptr<int[]> arr(new int[3]);
arr[0] = 1;
arr[1] = 2;
arr[2] = 3;
return 0;
}

数组版本使用 unique_ptr<T[]>,它会调用 delete[]

自定义删除器

当资源不是用 delete 释放时,可以提供删除器:

#include <cstdio>
#include <memory>

struct FileCloser {
void operator()(FILE* file) const {
if (file) {
std::fclose(file);
}
}
};

int main() {
std::unique_ptr<FILE, FileCloser> fp(std::fopen("data.txt", "w"));
if (fp) {
std::fputs("hello\n", fp.get());
}
return 0;
}

这让 unique_ptr 不仅能管内存,也能管文件句柄、套接字等资源。

使用注意

  1. 不要拷贝 unique_ptr,只能 std::move
  2. 移动后源指针通常为空,不要直接解引用。
  3. get() 只是观察,不转移所有权。
  4. 调用了 release() 就要负责后续释放,否则会泄漏。
  5. 尽量避免直接 new,优先 make_unique(可用时)。
  6. 需要共享所有权时,用 std::shared_ptr,不要硬把 unique_ptr 复制给多个地方。

小结

std::unique_ptr 是现代 C++ 里最基础也最重要的资源管理工具之一。它把“谁负责释放资源”这个问题变成编译期可检查的所有权模型,在保证性能的同时显著降低内存泄漏风险。掌握移动语义、resetrelease 和函数间传递模式后,基本就能覆盖多数日常使用场景。