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

std::move语义与push_back内直接构造对象的拷贝优化及正确用法

各案例行为说明
  • 案例1:vec.push_back(x) 这里x是左值,一定会触发拷贝构造,确实会产生不必要的拷贝,除非你后续还需要使用x对象。
  • 案例2:vec.push_back(Vector3d(a,b,c)) 这里传入的是临时对象(纯右值),从C11开始,push_back有接收右值引用的重载,会直接调用移动构造,不会产生额外拷贝。对于Eigen::Vector3d这种没有堆资源的类型,移动和拷贝开销一致,但如果是自定义带堆内存的类型,这里已经可以避免拷贝。另外C17起强制复制消除规则生效,连移动构造都可以省掉,直接在vector的内存空间上构造对象,零额外开销。
  • 案例3:vec.push_back(move(Vector3d(a,b,c))) 属于冗余写法。本身Vector3d(a,b,c)就是右值,不需要再套std::move做类型转换,最终效果和案例2完全一致,没有任何性能收益还会降低代码可读性。
更优的实现方式

还有两种更直接的零开销写法,自定义类和Eigen类型都适用:

  • 使用emplace_back:直接在vector管理的内存空间上构造对象,完全省去中间的临时对象构造+移动/拷贝步骤,写法也更简洁:
vec.emplace_back(a, b, c);

这个方法会直接把参数转发给Vector3d的构造函数,在vector的存储空间原地构造对象,是性能最优的选择。

  • 如果你已经有一个左值对象,且后续不再使用,可以显式用std::move转右值后push_back,避免拷贝:
auto x = Eigen::Vector3d(a,b,c);
// 此处执行其他需要用到x的操作,后续不再访问x
vec.push_back(std::move(x));

注意该写法执行后x处于被移动的状态,不要再读取它的取值。

补充说明

对于Eigen的固定大小类型(比如Vector3d、Matrix4d这类),因为内部数据全部存在栈上,没有动态申请的堆内存,所以移动构造和拷贝构造的开销完全一致,上述优化感知不明显。但如果是Eigen的动态大小矩阵/向量,或者你自定义的带堆内存的类(比如内部有std::string、std::vector成员),上述优化方案会带来非常明显的性能提升。

内容的提问来源于stack exchange,提问作者X.Arthur

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 12:54:01