智能指针——独占指针
智能指针
独占指针 —— unique_ptr
unique_ptr 用于表示对一块动态内存的唯一所有权,其核心特性如下:
- 同一时刻只能有一个指针拥有该内存资源
- 当
unique_ptr超出作用域时,所管理的内存会被自动释放 unique_ptr不可拷贝(Copy),但可以移动(Move),用于显式转移所有权
创建方式
unique_ptr 有多种创建方式,但在实际开发中,最推荐使用 make_unique。
独占指针的创建方式
// 1. 通过原始指针创建(不推荐)
cat* c_p1 = new cat("Tom");
std::unique_ptr<cat> u_c_p2(c_p1);
// 两个指针都能访问同一个对象
c_p1->cat_info();
u_c_p2->cat_info();
// 通过原始指针修改对象
c_p1->set_name("Jerry");
// unique_ptr 所指向的对象也随之改变
u_c_p2->cat_info();
// ⚠ 为了满足 unique_ptr 的独占语义,必须手动释放原始指针
c_p1 = nullptr;
// 2. 直接使用 new 创建(不推荐)
std::unique_ptr<cat> u_c_p3(new cat("Kitty"));
u_c_p3->cat_info();
// 3. 使用 make_unique 创建(最推荐)
std::unique_ptr<cat> u_c_p4 = std::make_unique<cat>("Mimi");
u_c_p4->cat_info();
说明:
- 前两种方式容易引入重复释放、异常安全问题
make_unique能保证异常安全,语义清晰,是现代 C++ 的推荐写法
传递方式
1. 值传递(不推荐)
值传递会涉及到所有权的转移。
由于 unique_ptr 不允许拷贝,必须显式使用 std::move 将所有权转移给函数参数。
这种方式会导致:
- 调用后原指针失效
- 每次传参都需要考虑所有权问题
- 使用成本和心智负担较高
值传递示例
void Foo(std::unique_ptr<cat> c)
{
c->cat_info();
}
int main()
{
std::unique_ptr<cat> c1 = std::make_unique<cat>("Mimi");
c1->cat_info();
// 显式转移所有权,c1 不再拥有该指针
Foo(std::move(c1));
// c1 已经失效,继续使用会出错
// c1->cat_info(); // 错误
// 临时对象会隐式触发 move
Foo(std::make_unique<cat>("111"));
}
2. 引用传递(推荐)
当函数不需要接管所有权,仅仅是使用对象时,应采用引用传递。
为了防止误操作修改指针本身,推荐使用 const std::unique_ptr<T>&:
- 可以访问对象
- 不能重置或转移指针
- 保证所有权仍归调用方
引用传递示例
void Foo1(const std::unique_ptr<cat>& c)
{
c->set_name("NewName");
c->cat_info();
// 不允许修改指针本身
// c.reset(); // 错误
}
int main()
{
std::unique_ptr<cat> c2 = std::make_unique<cat>("Jerry");
Foo1(c2);
c2->set_name("Tom");
c2->cat_info();
}
3. 作为返回值
unique_ptr 非常适合作为函数返回值。
编译器会自动使用移动语义(或 RVO),无需手动 std::move。
这种方式:
- 所有权语义清晰
- 不存在资源泄漏
- 支持链式调用
作为返回值示例
std::unique_ptr<cat> Foo2()
{
return std::make_unique<cat>("Kitty");
}
int main()
{
Foo2()->cat_info();
}
一句话总结
- 拥有资源 →
unique_ptr - 只使用、不接管 →
const unique_ptr& - 需要转移所有权 →
std::move - 创建对象 →
make_unique

浙公网安备 33010602011771号