C++中std::vector两种对象添加方式的差异及效率对比
问题解答:std::vector::push_back直接构造对象 vs 预先创建对象再添加的效率差异
好问题!咱们结合C++的版本特性和对象构造细节,来拆解这两种写法的效率差异:
先看两种实现的代码
方式一:push_back临时构造的对象
struct foo { int val; std::string str; foo(int _val, std::string _str) : val(_val), str(_str) {} }; int main() { std::vector<foo> list; std::string str("hi"); int val = 2; list.push_back(foo(val,str)); return 0; }
方式二:先创建对象再push_back
int main() { std::vector<foo> list; std::string str("hi"); int val = 2; foo f(val,str); list.push_back(f); return 0; }
效率差异分析
1. C++11之前的情况
在没有移动语义的年代,两种方式都会触发一次拷贝构造:
- 方式一:先构造临时
foo对象,再把这个临时对象拷贝到vector的内存中,最后临时对象被销毁。 - 方式二:先在栈上构造
foo f,再把f拷贝到vector的内存中,f会在main函数结束时才销毁。
此时两者的拷贝次数完全一致,效率差异几乎可以忽略——唯一的区别是临时对象的销毁时机,但这对性能影响极小,选哪种更多是代码风格问题。
2. C++11及之后的情况
C++11引入了右值引用和移动语义,这时候两种方式的差异就变得明显了:
- 方式一中的
foo(val, str)是临时对象(右值),push_back会调用foo的移动构造函数(如果没有自定义移动构造,编译器会生成默认版本)。对于std::string这种带堆内存资源的成员来说,移动操作只是转移内存指针,不需要复制字符串内容,效率比拷贝高很多。 - 方式二中的
f是左值,push_back会调用拷贝构造函数,需要完整复制str的内容到vector的新对象中,开销更大。
3. 极致优化:emplace_back
如果追求最高效率,更推荐使用std::vector::emplace_back,它可以直接在vector的内存空间中构造foo对象,完全避免拷贝或移动操作:
list.emplace_back(val, str); // 直接在vector的内存里构造foo,一步到位
总结
- 在C++11及之后的版本中,方式一(直接push_back临时对象)比方式二更高效,核心是利用移动语义减少了资源拷贝的开销。
- 如果你的代码适配C++11及以上,优先选方式一,或者更优的
emplace_back; - 在C++11之前,两者效率差异可以忽略,按自己习惯的风格写就行。
内容的提问来源于stack exchange,提问作者pattymills
相关产品推荐
相关产品推荐

