unique_ptr不能拷贝只因独占所有权,拷贝会导致double free;必须用std::move()转移,支持容器但需注意移动语义,初始化推荐std::make_unique,自定义删除器须匹配类型,裸指针移交后禁止再操作。

unique_ptr 为什么不能拷贝,只能移动
因为 unique_ptr 的设计目标就是「独占所有权」——同一时间只允许一个指针管理那块内存。一旦允许拷贝,就会出现两个指针同时指向同一块堆内存,析构时 double free 就不可避免。
编译器会直接报错,典型错误信息是:use of deleted function ‘std::unique_ptr<_tp _dp>::unique_ptr(const std::unique_ptr<_tp _dp>&)’</_tp></_tp>。
- 想“复制”语义?用
std::shared_ptr,不是unique_ptr - 真要转移所有权?必须显式调用
std::move(),比如传参或赋值时写func(std::move(p)) - 函数返回
unique_ptr是安全的:C++17 起 NRVO + 移动语义自动生效,不用手动std::move
如何正确初始化 unique_ptr(尤其带自定义删除器)
最常见错误是忽略删除器类型必须匹配——比如用 malloc 分配的内存,却用默认的 delete 删除器,UB(未定义行为)立刻触发。
初始化方式直接影响资源释放逻辑:
立即学习“C++免费学习笔记(深入)”;
- 默认构造:
std::unique_ptr<int> p;</int>→ 空指针,不管理任何资源 - 接管原始指针:
std::unique_ptr<int> p(new int(42));</int>(不推荐,异常不安全) - 推荐写法:
std::unique_ptr<int> p = std::make_unique<int>(42);</int></int>(异常安全,且 C++14+ 支持数组:std::make_unique<int>(10)</int>) - 带自定义删除器:
std::unique_ptr<int void> p(ptr, [](int* p){ free(p); });</int>—— 注意删除器类型必须作为模板参数显式写出,否则编译失败
unique_ptr 在容器里怎么用才不出问题
可以放进 std::vector、std::map 等标准容器,但前提是容器操作不触发拷贝——而 unique_ptr 容器恰恰依赖移动语义工作。
常见翻车点:
-
vec.push_back(p)编译失败:因为p是左值,需写成vec.push_back(std::move(p)) - 用
emplace_back更安全:vec.emplace_back(new int(10))或更好是vec.emplace_back(std::make_unique<int>(10))</int> - 遍历时别用引用取内容再 move:比如
for (auto& x : vec) { use(std::move(x)); }会导致后续迭代访问已为空的unique_ptr,容易 segfault - 容器元素被移动后,对应位置变成空指针,
operator bool()返回false,记得判空
和裸指针混用时最容易漏掉的三件事
很多人以为 “先用 new,再交给 unique_ptr” 很自然,但实际埋了三个隐性雷:
- 裸指针一旦交给
unique_ptr,就绝对不能再用delete手动释放,否则 double free;也不可重复构造另一个unique_ptr指向它 -
unique_ptr.get()返回的是裸指针,仅作临时观察或传给 C 接口用;绝不能存起来长期持有,因为unique_ptr析构后它就悬空 -
unique_ptr.release()交出所有权后,原unique_ptr变为空,但你得自己负责后续释放——这等于退化回裸指针管理,除非有强理由,否则不建议用
真正难的不是语法,是所有权边界是否清晰。只要哪一行代码让两个变量能同时影响同一块内存,问题就藏在那里。









