unique_ptr不能拷贝只因独占所有权设计,防止double-free;编译器删除拷贝函数,仅保留移动操作;需用std::move()转移所有权,传参用&&或传值,返回时编译器自动移动。

unique_ptr 为什么不能拷贝,只能移动
因为 unique_ptr 的设计目标就是「独占所有权」——同一块内存绝不允许两个指针同时管理,否则析构时会 double-free。C++ 直接删掉了拷贝构造函数和拷贝赋值运算符,只保留移动构造和移动赋值。
常见错误现象:error: use of deleted function 'std::unique_ptr<t>::unique_ptr(const std::unique_ptr<t>&)'</t></t>
- 想“复制”一个
unique_ptr?不行,必须用std::move()转移所有权 - 函数参数要接收独占资源?声明为
std::unique_ptr<t>&&</t>或直接传值(触发移动) - 返回局部
unique_ptr?放心 return,现代编译器会自动移动(RVO + 移动语义)
如何正确初始化 unique_ptr(尤其带自定义删除器)
默认构造、new 初始化、make_unique 是三种主流方式,但行为有关键差异:前者不分配内存,后两者才真正 new 对象;而 make_unique 更安全(异常安全、无裸 new)。
使用场景:需要控制资源释放逻辑(比如关闭文件、卸载 DLL、调用 C API 的 free 函数)时,必须绑定自定义删除器。
立即学习“C++免费学习笔记(深入)”;
- 默认初始化:
std::unique_ptr<int> p1;</int>→ 空指针,p1.get() == nullptr - 裸 new 初始化:
std::unique_ptr<int> p2(new int(42));</int>→ 不推荐,异常可能造成泄漏 - 推荐写法:
auto p3 = std::make_unique<int>(42);</int> - 带删除器(例如 FILE*):
std::unique_ptr<file decltype> fp(fopen("log.txt", "w"), &fclose);</file>
reset()、release() 和 get() 的区别与误用风险
这三个函数都操作底层裸指针,但语义完全不同:reset() 交还所有权并释放资源;release() 交还所有权但不释放;get() 只读取地址,不改变所有权。
容易踩的坑:用 get() 返回的指针去 delete,或对已 release() 的 unique_ptr 再调用 reset() —— 都会导致未定义行为或内存泄漏。
-
p.reset(new int(100));→ 原对象被 delete,p 指向新对象 -
int* raw = p.release();→ p 变成空,raw 必须手动 delete(或交给别的智能指针) -
int* x = p.get();→ x 是只读快照,改 x 不影响 p,也不能 delete x - 危险操作:
delete p.get();→ 重复析构,崩溃大概率发生
在容器中存 unique_ptr 时要注意什么
vector、map 等容器可以安全持有 unique_ptr,因为它们内部使用移动而非拷贝来管理元素——但这要求你插入时也主动提供可移动对象,否则编译失败。
性能影响:存储 unique_ptr 本身只占一个原生指针大小(8 字节),比存对象本体更轻量,适合大对象或不支持拷贝的类型。
- 往
std::vector<:unique_ptr>></:unique_ptr>添加元素:v.push_back(std::make_unique<int>(i));</int>或v.emplace_back(new int(i)); - 不能写:
v.push_back(*p);或v.push_back(p);(拷贝被禁) - 遍历时解引用:
for (const auto& ptr : v) { std::cout - 注意:容器析构时会自动调用每个
unique_ptr的析构函数,无需手动清理
最常被忽略的一点:自定义删除器的类型是 unique_ptr 类型的一部分。这意味着 std::unique_ptr<int></int> 和 std::unique_ptr<int mydeleter></int> 是完全不同的类型,不能混用,也无法隐式转换。










