std::unique_ptr传递即转移所有权,原指针置空,目标接管生命周期;必须用std::move()显式转移,因拷贝构造/赋值被删除;返回时自动移动,无需std::move。

传递 unique_ptr 就是在转移所有权
当你把一个 std::unique_ptr 传给函数,或者赋值给另一个 unique_ptr 变量,你不是在复制它——而是在把资源的“处置权”交出去。这个动作本身会清空原指针(变成 nullptr),目标方则接管对象生命周期。编译器强制你用 std::move() 显式表达这个意图,否则直接报错。
- 函数参数用值传递(
void f(std::unique_ptr<t> p)</t>):调用时必须写f(std::move(ptr)),ptr进入函数后即失效 - 函数参数用右值引用(
void f(std::unique_ptr<t>&& p)</t>):也能接收std::move(ptr),但更常见于转发场景,不推荐作为常规接口 - 函数参数用 const 引用(
const std::unique_ptr<t>& p</t>):只能读取,不能转移,也拿不到裸指针(p.get()可用,但不改变所有权) - 返回
std::unique_ptr:函数内创建并返回,调用方自动获得所有权,无需std::move(NRVO 或移动返回已由编译器优化)
为什么不能按值传递而不加 std::move?
因为 std::unique_ptr 的拷贝构造函数和拷贝赋值运算符被显式删除(= delete)。这是编译期硬约束,不是风格建议。试图写 func(ptr) 会触发类似这样的错误:
error: use of deleted function ‘std::unique_ptr<int>::unique_ptr(const std::unique_ptr<int>&)’</int></int>
它堵死了所有隐式复制路径,确保“谁创建、谁移交、谁销毁”的链条清晰可溯。
容易踩的坑:释放后还解引用
所有权转移后,原 unique_ptr 变成空,但它的类型仍是 std::unique_ptr<t></t>,不会自动变为 nullptr 类型——只是内部指针为 nullptr。继续用 *ptr 或 ptr->foo() 会触发运行时崩溃(segmentation fault)。
- 别依赖未定义行为来“测试是否为空”,始终用
if (ptr)或if (ptr != nullptr)显式判空 - 避免在转移后仍持有对原变量的引用或别名(比如
auto& ref = ptr再std::move(ptr),ref 会悬空) - 容器中存
std::unique_ptr时,用std::vector<:unique_ptr>>::emplace_back(std::make_unique<t>())</t></:unique_ptr>,别用push_back加裸指针再包装
什么时候该用 get() 而不是转移?
当函数只需要临时访问对象、不参与生命周期管理时,用 ptr.get() 拿裸指针最安全。典型场景包括:
- 调用 C 风格 API(如
write(fd, ptr.get(), size)) - 传给只读函数(如
print_value(*ptr.get())) - 调试打印:
std::cout
注意:get() 返回的指针寿命严格依附于 unique_ptr 本身;一旦 ptr 被 reset()、离开作用域或被移动,该裸指针立刻失效。
std::unique_ptr 的唯一合法交互方式,所有“意外空指针”或“双重释放”问题,几乎都源于混淆了“访问”和“接管”这两个动作。C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











