You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何将shared_ptr传入函数前需创建本地副本?解析两类典型问题

解析CppCon 2015中shared_ptr的两类使用风险及解决方案

先看你提到的代码示例:

void f(int*);
void g(shared_ptr<int>&, int*);
shared_ptr<int> gsp = make_shared<int>();

int main()
{
  // Issue 1>
  f(gsp.get()); // ERROR, arg points to gsp', and gsp is modifiable by f
  // Solution 1>
  auto sp = gsp;
  f(sp.get());  // ok. arg points to sp', and sp is not modifiable by f

  // Issue 2>
  g(sp, sp.get());  // ERROR, arg2 points to sp', and sp is modifiable by f
  // Solution 2>
  g(gsp, sp.get()); // ok, arg2 points to sp', and sp is not modifiable by f
}

针对Issue 1的解释

问题本质

直接调用f(gsp.get())时,gsp是全局可修改的shared_ptr。f虽接收原始指针,但如果f内部通过全局引用、闭包捕获等途径修改gsp(比如调用gsp.reset()让它放弃当前对象所有权),f手里的原始指针会立刻变成悬空指针,后续访问会触发未定义行为(程序崩溃、数据错乱等)。

解决方案原理

auto sp = gsp;完成了shared_ptr的拷贝,底层int对象的引用计数+1。这个局部sp完全由当前代码块控制,f没有任何方式修改它。只要sp生命周期未结束(当前代码块内),它持有的对象就不会被销毁,sp.get()得到的原始指针在f执行期间绝对安全,不会悬空。

针对Issue 2的解释

问题本质

调用g(sp, sp.get())时,g的第一个参数是shared_ptr<int>&,意味着g可以直接修改传入的sp(比如在g内部调用sp.reset()切换指向对象)。而第二个参数是sp当前指向对象的原始指针,若g先修改了sp,第二个参数的原始指针会立刻悬空,后续使用必然触发未定义行为。

解决方案原理

g(gsp, sp.get())将两个参数拆分为独立的gsp和sp:g可以修改gsp,但这不会影响局部sp——sp仍持有原对象,引用计数保证对象不会被销毁。因此sp.get()得到的原始指针在g执行全程都有效,不会因g修改gsp而悬空。

内容的提问来源于stack exchange,提问作者q0987

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 19:11:30