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

为何std::push_back()表现类似std::emplace_back()?构造调用疑问

关于std::vector push_back的构造调用疑问解答

问题场景

在未调用reserve()的std::vector中执行push_back(std::move(three))时,输出先出现“move constructed”,随后又出现“copy constructed”。原本认为push_back会先在容器外构造对象再拷贝至容器,而emplace_back直接在容器内完成对象创建、拷贝或移动,但实际表现和认知不符,存在两个疑问:

  1. 最后一次push_back为何先调用移动构造函数再调用拷贝构造函数?
  2. 为何push_back的表现与emplace_back相似?

疑问解答

1. 先移动再拷贝的原因

这是因为vector扩容触发的元素转移导致的:

  • 第一步,push_back(std::move(three))会直接把three移动到vector当前的末尾位置(此时这个位置还在旧的内存缓冲区里),所以触发一次移动构造。
  • 第二步,vector检查到当前容量已经耗尽,必须扩容。此时需要把旧内存里的所有元素(包括刚移动进来的那个)转移到新分配的更大内存中。如果你的元素类型的移动构造函数没有标记为*noexcept*,vector为了保证异常安全,会选择用拷贝构造来转移元素——因为如果移动过程中抛出异常,旧元素可能已经被破坏,无法回滚;但拷贝的话,旧元素还保持完好,能安全恢复操作。

简单总结:先移动构造新元素到旧内存,扩容时因移动构造不保证异常安全,只能拷贝所有元素到新内存,所以出现两次构造调用。

2. push_back和emplace_back表现相似的原因

你的旧认知存在偏差:

  • push_back并非总是先在容器外构造再拷贝。当传入的是右值(比如std::move(three)),push_back会直接在容器的内存空间里移动构造元素,而非先构造再拷贝。
  • emplace_back的核心是通过完美转发参数,直接在容器内存里构造元素;而push_back对右值的处理,本质也是利用完美转发,直接在容器内完成构造(移动或拷贝)。两者在处理右值时的底层逻辑高度一致,所以表现会相似。

举个直观的例子:push_back(std::move(obj))和emplace_back(std::move(obj))的效果几乎完全相同,都是直接在容器内存里移动构造元素;只有当传入左值时,两者才会一致地触发拷贝构造(除非手动将左值转为右值)。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 03:13:11