emplace_back是C++11引入的容器成员函数,它直接在vector底层内存上原地调用元素类型的构造函数,避免临时对象构造和移动/拷贝开销;而push_back需先构造临时对象再移入容器,对复杂类型性能损耗明显。

emplace_back 是什么,为什么比 push_back 快
它不是“更快地插入”,而是“跳过临时对象构造 + 移动/拷贝”——emplace_back 直接在 vector 底层内存上原地调用元素类型的构造函数,不生成中间临时对象。push_back 则必须先构造临时对象(或接受右值并移动),再把它挪进容器。对复杂类型(比如含 string 成员的 struct、自定义类),这多出的构造+移动开销很可观。
哪些场景下 emplace_back 真正生效
只有当你传入的参数能直接匹配目标类型的某个构造函数时,emplace_back 才会原地调用该构造函数。否则它退化为等价于 push_back(std::forward,甚至可能编译失败。
- ✅ 有效:向
std::vector<:string>插入v.emplace_back("hello")→ 调用string(const char*) - ✅ 有效:向
std::vector插入v.emplace_back("Alice", 28)→ 若Person有Person(std::string, int)构造函数 - ❌ 无效:写成
v.emplace_back(std::string("Bob"))→ 先构造临时std::string,再转发给emplace_back,失去意义 - ⚠️ 编译失败:若
Person只有默认构造函数,却写v.emplace_back(42),会报错找不到匹配构造函数
常见误用和性能陷阱
很多人以为 “用了 emplace_back 就一定快”,但实际中几个典型反模式反而更慢或出错:
- 对 trivial 类型(如
int、double)用emplace_back没收益,编译器优化后两者完全等价 - 传入已存在的对象(如
v.emplace_back(x)),会触发拷贝构造(而非移动),比push_back(std::move(x))还差 - 构造函数抛异常时,
emplace_back的异常安全性与push_back一致,但调试栈更难读——因为构造发生在容器内部,堆栈里看不到“谁在 new 对象” - 如果类型禁止拷贝/移动(如删掉移动构造函数),
push_back会编译失败;而emplace_back只要构造函数可用,仍可工作
一个可验证的对比示例
下面代码模拟一个带日志的构造过程,能看出调用次数差异:
立即学习“C++免费学习笔记(深入)”;
#include#include struct Heavy { Heavy() { std::cout << "default ctor\n"; } Heavy(int x) : val(x) { std::cout << "int ctor: " << x << "\n"; } Heavy(const Heavy&) { std::cout << "copy ctor\n"; } Heavy(Heavy&&) noexcept { std::cout << "move ctor\n"; } int val; }; int main() { std::vector
v; std::cout << "--- push_back ---\n"; v.push_back(Heavy(42)); // 输出:int ctor → copy ctor std::cout << "--- emplace_back ---\n"; v.emplace_back(42); // 输出:int ctor(仅一次) }
输出清晰显示:push_back(Heavy(42)) 触发两次构造(先建临时对象,再拷贝进 vector),而 emplace_back(42) 只调用一次构造函数。
注意:如果你用的是 C++17 或更高版本,push_back(Heavy(42)) 可能被强制省略拷贝(RVO/NRVO),但这是编译器优化行为,不可依赖;而 emplace_back 的原地构造语义是标准保证的。









