emplace_back更快是因为它在容器尾部原地构造对象,避免拷贝或移动;而push_back需先构造临时对象再拷贝/移动,对不可拷贝或大对象性能差异显著。

emplace_back 为什么比 push_back 更快
因为 emplace_back 在容器尾部**原地构造对象**,不触发拷贝或移动;而 push_back 先构造临时对象,再将其拷贝/移动进容器。尤其对含非平凡构造函数、不可拷贝(如 std::unique_ptr)或大对象的类型,性能差异明显。
但这个优势只在「构造参数能直接传给元素类型的构造函数」时生效——否则编译失败或退化为隐式转换 + 拷贝。
- ✅ 正确:容器是
vector,调用> v.emplace_back(42, "hello") - ❌ 错误:
v.emplace_back({42, "hello"})—— 这会先构造std::initializer_list,再尝试匹配构造函数,通常不匹配且效率低 - ⚠️ 注意:若元素类型只有默认构造函数,
emplace_back()合法但无性能收益
哪些 STL 容器支持 emplace_back
仅限支持在尾部高效插入的序列容器:std::vector、std::deque、std::list。它们都提供 emplace_back 成员函数。
std::array 不支持(固定大小,无动态插入);std::forward_list 只有 emplace_front;关联容器(如 std::map)用的是 emplace 或 try_emplace,不是 emplace_back。
立即学习“C++免费学习笔记(深入)”;
- ✅
vectorv; v.emplace_back(10); - ✅
dequed; d.emplace_back("abc"); - ❌
array—— 编译错误a; a.emplace_back(1);
emplace_back 的常见误用与崩溃场景
最典型的坑是传参类型不匹配导致调用错误重载,或引发未定义行为。比如容器元素是 std::string,却传入 nullptr:
启科网络商城系统由启科网络技术开发团队完全自主开发,使用国内最流行高效的PHP程序语言,并用小巧的MySql作为数据库服务器,并且使用Smarty引擎来分离网站程序与前端设计代码,让建立的网站可以自由制作个性化的页面。 系统使用标签作为数据调用格式,网站前台开发人员只要简单学习系统标签功能和使用方法,将标签设置在制作的HTML模板中进行对网站数据、内容、信息等的调用,即可建设出美观、个性的网站。
vectorv; v.emplace_back(nullptr); // 编译通过,但运行时崩溃(构造空指针 string)
另一个陷阱是移动后使用被移出的对象:
- ✅
v.emplace_back(std::move(s));——s被移走,之后不应再读取 - ❌
v.emplace_back(s); v.push_back(s);—— 若s是右值引用或已 move,第二次用可能出错 - ⚠️ 对于自定义类型,确保其构造函数是
noexcept(尤其在vector扩容时),否则异常可能导致容器状态不一致
性能优化要结合实际数据结构和场景
别盲目替换所有 push_back 为 emplace_back。如果对象本身是 trivial 类型(如 int、double),两者生成的汇编几乎一样;如果构造逻辑复杂但参数来自已有变量(而非字面量),反而可能因强制完美转发引入额外开销。
真正值得优化的场景是:频繁插入、对象构造代价高、且参数可直接传递(比如从函数返回值、tuple 解包、或常量字面量)。
- ✅ 高效:
vec.emplace_back(make_pair(key, std::move(value))); - ✅ 高效:
vec.emplace_back(1, "a", 3.14f);(对应三参数构造) - ❌ 过度:
auto x = expensive_func(); vec.emplace_back(x);—— 和push_back(x)几乎没差别
是否提升性能,最终得看 profile 数据——尤其是构造函数耗时占比和内存分配次数。有时候 reserve + emplace_back 才是组合拳的关键。








