std::unique_ptr禁止拷贝只允许移动,因其独占所有权且无引用计数,拷贝会导致double free;正确做法是用std::move移交所有权,原指针置空。

std::unique_ptr 为什么禁止拷贝、只允许移动
因为它的设计目标就是“独占所有权”——同一时间只能有一个 unique_ptr 持有该资源。底层没有引用计数,析构时直接调用删除器(默认 delete)释放内存。如果允许拷贝,两个对象会在各自析构时都尝试 delete 同一块内存,触发 double free。
常见错误现象:error: use of deleted function 'unique_ptr(const unique_ptr&)'。遇到这个报错,不是编译器太严,而是你在试图复制一个本就不该被复制的东西。
- 正确做法:用
std::move()显式移交所有权,原unique_ptr变成空状态(get() == nullptr) - 自定义删除器必须是可移动的,否则
unique_ptr移动构造会失败 - 性能上几乎零开销:不分配额外控制块,
sizeof(unique_ptr<t>)</t>通常等于原始指针大小
std::shared_ptr 的控制块到底存在哪
shared_ptr 的引用计数、删除器、分配器等元数据都存在一个独立的“控制块”(control block)里,而不是和托管对象绑在一起——除非你用 make_shared。
两种构造方式的内存布局差异极大:
-
shared_ptr<t>(new T)</t>:对象和控制块分别在堆上两块独立内存,多一次malloc,缓存不友好 -
make_shared<t>()</t>:控制块和对象在同一块连续内存中分配,减少内存碎片和分配次数,但无法单独定制对象的分配器
注意:weak_ptr 和 shared_ptr 共享同一个控制块,但它不增加强引用计数(use_count),只影响弱引用计数(weak_count)。
循环引用不是 shared_ptr 的 bug,而是用法错误
典型场景:A 持有 shared_ptr<b></b>,B 又持有 shared_ptr<a></a>。即使所有外部 shared_ptr 都离开作用域,A 和 B 的引用计数也永远不会降到 0,导致内存泄漏。
这不是引用计数机制的问题,而是所有权图出现了闭环。解决的关键不是“换别的智能指针”,而是打破闭环:
- 一方改用
weak_ptr(比如 B 改用weak_ptr<a></a>),访问前调用lock()转成临时shared_ptr - 避免在类成员中双向持有
shared_ptr,优先考虑组合或依赖注入,而非互相持有 - 用
enable_shared_from_this时,确保对象本身已被shared_ptr管理,否则shared_from_this()抛std::bad_weak_ptr
weak_ptr.lock() 返回空,不代表对象已销毁
weak_ptr 的 lock() 返回 shared_ptr,若返回空,只说明“当前时刻强引用计数为 0”,但控制块可能还活着(比如还有其他 weak_ptr 存在,weak_count > 0)。
容易踩的坑:
- 把
weak_ptr当作“安全裸指针”用,不检查lock()结果就解引用 → crash - 在多线程中反复调用
lock()判断对象是否存活,不如先lock()得到一个shared_ptr,再用它做后续操作(避免竞态) -
use_count()是非原子读,仅作调试参考;生产环境判断有效性必须靠lock().get() != nullptr
shared_ptr 实例都在悄悄延长对象生命周期,而 weak_ptr 又让这种延长变得不可见。一旦所有权关系脱离代码结构本身,只靠运行时行为去推理,就很容易漏掉某个 weak_ptr 正在拖住控制块。C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











