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

使用条件运算符配合std::move操作shared_ptr出现异常行为的原因

条件运算符导致std::shared_ptr被意外移动的原因分析

核心问题:条件运算符的强制类型统一规则

C++里的?:条件运算符有个硬性要求:两个分支的表达式结果必须是同一类型(或者能隐式转换成同一个类型)。看你代码里的两个分支:

  • std::move(ptr)的类型是std::shared_ptr<int>&&(右值引用)
  • std::shared_ptr<int>(ptr)是临时的std::shared_ptr<int>对象(右值)

编译器为了让两个分支类型统一,会把它们都转成std::shared_ptr<int>。对于std::move(ptr)这个右值引用,转换的方式就是调用shared_ptr的移动构造函数,生成一个临时的shared_ptr对象——这一步直接把ptr持有的资源偷走了,ptr当场就变成空的了。

也就是说,不止最后一次循环,前9次循环每次都会把ptr的资源移走。第一次循环结束后ptr已经是空指针了,后面的循环里拷贝构造出来的临时对象也都是空的,最后自然输出ptr is null。

if-else为啥不一样?

if-else是两个完全独立的语句块,没有强制类型统一的要求:

  • 前9次循环:std::shared_ptr<int>(ptr)是拷贝构造临时对象,ptr的引用计数临时加1,临时对象销毁后计数又减回去,ptr的资源从头到尾都没动过。
  • 最后一次循环:std::move(ptr)只是把ptr转成右值引用传给func的参数,但func里啥也没干——既没拿这个右值引用构造新对象,也没做移动赋值,所以ptr的资源根本没被窃取,自然还是有效的。

怎么让条件运算符和if-else行为一致?

只要让两个分支的类型统一成右值引用,避免编译器生成移动构造的临时对象就行:

func(i == 9 ? std::move(ptr) : std::move(std::shared_ptr<int>(ptr)));

这时两个分支都是std::shared_ptr<int>&&类型,不需要额外转换。前9次循环只会拷贝构造临时对象后再移动(但临时对象的资源会传给func,ptr不受影响),最后一次才会移动ptr,但func不操作资源,最终ptr仍然有效。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 10:35:29