C++怎么使用shared_ptr_C++资源管理教程【共享】

2次阅读

shared_ptr构造传nullptr不会崩溃,但解引用会触发未定义行为;reset()释放旧资源且不影响其他共享者,而=赋值更安全且原子;make_shared更高效因单次分配;循环引用需用weak_ptr破。

C++怎么使用shared_ptr_C++资源管理教程【共享】

shared_ptr 构造时传 nullptr 会崩溃吗

不会崩溃,但容易误以为“安全”而忽略后续解引用风险。std::shared_ptr<int> p(nullptr)</int> 是合法的,p 确实持有空指针、引用计数为 1,但一旦写 *pp->xxx 就触发未定义行为(通常是段错误)。

  • 常见错误现象:shared_ptr 从工厂函数返回前被意外赋值为 nullptr,调用方没检查就直接解引用
  • 正确做法:构造后用 if (p)p != nullptr 显式判空,别依赖隐式转换
  • 注意:shared_ptr<t>()</t>shared_ptr<t>(nullptr)</t> 效果一致,但后者语义更明确

reset() 和赋值 = 的区别在哪

关键在是否释放旧资源、是否影响其他共享该对象shared_ptr 实例。

  • p.reset(new int(42)):先释放 p 当前持有的资源(如果非空),再接管新对象;其他同享该对象的 shared_ptr 不受影响
  • p = std::make_shared<int>(42)</int>:同样会释放旧资源,但更安全(避免裸指针泄漏);且 = 是原子操作,适合线程场景下替换整个智能指针
  • 坑点:p.reset()(无参)等价于 p.reset(nullptr),会清空指针但保留控制块——内存没全释放,可能造成轻微浪费

为什么 make_shared 比 shared_ptr(new T) 更高效

因为一次内存分配搞定控制块 + 对象本体,而 shared_ptr(new T) 至少要两次分配(new 一次,控制块再 new 一次)。

  • 性能影响:小对象差异不明显,但高频创建时分配次数减半,缓存局部性更好
  • 兼容性限制:make_shared 要求 T构造函数可访问(不能是私有或 explicit 构造函数被隐式调用)
  • 例外场景:需要自定义删除器(deleter)或别名构造(aliasing constructor)时,只能用 shared_ptr 构造函数,不能用 make_shared

循环引用导致内存泄漏怎么破

两个 shared_ptr 相互持有对方所管对象,引用计数永远不归零,析构不触发。

立即学习C++免费学习笔记(深入)”;

  • 典型场景:父子结构(如树节点)、观察者模式中回调捕获自身 shared_ptr
  • 解法:把其中一端改成 std::weak_ptr,访问前用 lock() 升级成临时 shared_ptr,失败说明对象已销毁
  • 容易踩的坑:在 Lambda 中捕获 shared_ptr 后又把它赋给成员变量,形成隐式循环;改用 [weak = weak_from_this()] 捕获更安全

c++shared_ptr 不是万能胶水,它只解决“谁负责释放”的问题,不自动解决“谁该持有”和“何时持有”的逻辑问题。最常出错的地方,恰恰藏在看似最省事的写法里——比如直接 = 赋值、不检查空、或者在闭包里随手捕获 this

text=ZqhQzanResources