emplace_back是C++11引入的容器成员函数,它直接在vector底层内存上原地调用元素类型的构造函数,避免临时对象构造和移动/拷贝开销;而push_back需先构造临时对象再移入容器,对复杂类型性能损耗明显。
它不是“更快地插入”,而是“跳过临时对象构造 + 移动/拷贝”——emplace_back 直接在 vector 底层内存上原地调用元素类型的构造函数,不生成中间临时对象。push_back 则必须先构造临时对象(或接受右值并移动),再把它挪进容器。对复杂类型(比如含 string 成员的 struct、自定义类),这多出的构造+移动开销很可观。
只有当你传入的参数能直接匹配目标类型的某个构造函数时,emplace_back 才会原地调用该构造函数。否则它退化为等价于 push_back(std::forward(args)...),甚至可能编译失败。
std::vector<:string> 插入 v.emplace_back("hello") → 调用 string(const char*)
std::vector 插入 v.emplace_back("Alice", 28) → 若 Person 有 Person(std::string, int) 构造函数v.e
mplace_back(std::string("Bob")) → 先构造临时 std::string,再转发给 emplace_back,失去意义Person 只有默认构造函数,却写 v.emplace_back(42),会报错找不到匹配构造函数很多人以为 “用了 emplace_back 就一定快”,但实际中几个典型反模式反而更慢或出错:
int、double)用 emplace_back 没收益,编译器优化后两者完全等价v.emplace_back(x)),会触发拷贝构造(而非移动),比 push_back(std::move(x)) 还差emplace_back 的异常安全性与 push_back 一致,但调试栈更难读——因为构造发生在容器内部,堆栈里看不到“谁在 new 对象”push_back 会编译失败;而 emplace_back 只要构造函数可用,仍可工作下面代码模拟一个带日志的构造过程,能看出调用次数差异:
#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 的原地构造语义是标准保证的。