std::shared_ptr 转换不会导致内存泄漏,只要使用 std::static_pointer_cast 复用原控制块(含删除器、引用计数等);错误做法如 std::shared_ptr(ptr.get()) 或 static_cast 会丢弃控制块,引发未定义行为。
std::shared_ptr
转 std::shared_ptr不会内存泄漏
只要原始
的析构函数能正常调用(即 T 的析构是平凡或已定义的),转成
后,对象仍会被正确销毁。关键不在类型擦除,而在控制块是否保存了正确的删除器。
转换时必须显式指定删除器,否则可能崩溃或未定义行为
默认构造的
没有绑定删除逻辑;直接用
或隐式转换会丢失原始删除器,导致
作用于
—— 这是未定义行为,常见表现是析构函数不执行、内存未释放、或程序崩溃。
✅ 正确做法:用
或
⚠️ 错误写法:
—— 丢弃控制块,只剩裸指针
⚠️ 错误写法:
—— C++ 不允许这样 cast
std::static_pointer_cast
是最安全的转换方式
它复用原
的控制块,包括自定义删除器、引用计数、分配器等全部状态,只是把存储的指针类型从
改为
。适用于需要泛型持有、跨模块传递、或与 C 接口桥接的场景。
C知道
CSDN推出的一款AI技术问答工具
下载
支持自定义删除器(比如用
分配的内存)
保持线程安全的引用计数操作
不增加额外开销,底层控制块零拷贝
不能反向转回
(类型信息已擦除),除非你存了原始类型指针或用
(仅限多态)
析构时机只取决于引用计数,和 void 转换无关
和
共享同一控制块,只要还有任一实例存活,对象就不会析构。哪怕所有变量都是
类型,只要引用计数没归零,析构器就还在那儿等着。
立即学习
“
C++免费学习笔记(深入)
”;
常见误判点:看到
就以为“类型丢了,没法析构”——实际析构逻辑全在控制块里
注意:如果原始
是用默认删除器 +
构造的,那
后仍会调用
,不是
真正危险的是绕过控制块自己 new + 手动管理,或误用
配合
指针
类型擦除本身不破坏生命周期管理,但任何跳过控制块的指针提取(比如调用
后另起一个
)都会切断析构链。别碰裸指针,别手写删除器逻辑,别信“void 就是不管了”。
std::shared_ptrstd::shared_ptrstd::shared_ptrstatic_castdeletevoid*std::shared_ptr(ptr, ptr.get_deleter()) std::static_pointer_cast(ptr) std::shared_ptr(ptr.get()) static_cast<:shared_ptr>>(ptr)shared_ptrshared_ptrT*void*freestd::shared_ptrdynamic_pointer_caststd::shared_ptrstd::shared_ptrvoidvoid*shared_ptrnew Tstatic_pointer_castT::~T()operator delete(void*)reset(new T)void.get()shared_ptr