C++怎么使用智能指针_C++内存管理教程【现代】

7次阅读

std::unique_ptr必须用std::make_unique初始化以避免内存泄漏;shared_ptr循环引用需用weak_ptr打破;禁止混用智能指针与裸指针进行双重管理或释放操作。

C++怎么使用智能指针_C++内存管理教程【现代】

std::unique_ptr 怎么初始化才不会崩溃

直接用裸指针初始化 std::unique_ptr 是最常见崩点。比如写 std::unique_ptr<int> p(new int(42))</int> 看似没问题,但一旦构造函数抛异常(比如 int 的构造里 throw),new 出来的内存就泄露了——因为 unique_ptr 构造还没完成,析构器根本没接管。

正确做法只有一条:用 std::make_unique

  • std::make_unique<int>(42)</int> —— 安全,分配和构造原子完成
  • 别手动 new + 传入构造函数,尤其别对数组用 std::unique_ptr<int>(new int[10])</int>,应改用 std::make_unique<int>(10)</int>
  • 如果必须从裸指针接手(比如 C API 返回的指针),用 std::unique_ptr<t>(raw_ptr)</t> 后立刻检查 raw_ptr != nullptr,否则空指针移交会调用 delete nullptr(虽标准允许,但某些自定义 deleter 会崩)

std::shared_ptr 循环引用怎么破

两个 std::shared_ptr 互相持有对方管理的对象,引用计数永远不降到 0,对象就永远不释放——典型场景是父子结构、观察者回调、Lambda 捕获自身 shared_ptr

核心解法不是“少用 shared_ptr”,而是明确谁该强引用、谁该弱引用。

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

  • 父持有子用 std::shared_ptr,子反向引用父必须用 std::weak_ptr
  • 在 lambda 里捕获 shared_ptr 自身?改成捕获 weak_ptr,调用前用 lock() 转成临时 shared_ptr,失败就说明对象已销毁
  • 别用 shared_from_this() 在构造函数里调用——此时控制块还没建好,行为未定义

智能指针和 raw pointer 混用时哪些操作绝对不能做

混用本身不违法,但几类操作一做就踩内存或 double-free。

  • std::unique_ptr.get() 返回的裸指针再传给另一个智能指针构造(比如又塞进 std::shared_ptr)——双重管理,必崩
  • get() 出来的指针调用 deletefree——智能指针还在管,释放后变成悬垂指针
  • std::shared_ptrget() 结果存成全局裸指针并长期使用——忘了它可能随时被释放,下次访问就是 UAF
  • std::shared_ptr 管理对象(比如 int x; std::shared_ptr<int>(&x)</int>)——析构时 delete 栈地址,UB

move 语义下 unique_ptr 和 shared_ptr 行为差异

看起来都是“转移所有权”,但底层动作完全不同,影响性能和线程安全。

  • std::unique_ptr move 是纯指针赋值+置空,零开销,无原子操作,线程间传递需自行同步
  • std::shared_ptr move 会把控制块里的引用计数从源减 1、目标加 1,但 move 本身不修改引用计数(只转移控制块指针),所以比 copy 快,但仍涉及一次指针复制和原对象置空
  • 别对 shared_ptr 频繁 move 来“优化性能”——除非你在 hot path 且 profile 确认控制块访问是瓶颈,否则收益极小,还增加理解成本
  • move 后原 unique_ptr 变成空,访问 get() 返回 nullptr;而 shared_ptr move 后也为空,但它的控制块可能还在被其他副本引用

智能指针不是银弹,真正难的从来不是语法,而是判断“谁该拥有所有权”“生命周期边界在哪”。很多 crash 其实发生在跨模块、跨线程、或和 C 风格 API 交互时——那里没有自动管理,只有你写的那行 reset()release() 是否恰到好处。

text=ZqhQzanResources