C++STL之push_back()和emplace_back
🆚 一句话区别
push_back()
和emplace_back()
都是std::vector
、std::deque
等容器的方法,用于向容器末尾添加元素,但它们的机制和效率有明显不同。
push_back()
是复制或移动一个已存在的对象进去,
emplace_back()
是直接在容器内部原地构造对象,避免拷贝/移动。
1️⃣ push_back()
的原型和行为
template<typename T>
void push_back(const T& value); // 拷贝
void push_back(T&& value); // 移动(C++11)
你需要先构造好一个对象,然后把它加进去。
🔧 示例:
std::vector<std::string> vec;
std::string s = "hello";
vec.push_back(s); // 拷贝
vec.push_back(std::move(s)); // 移动
vec.push_back("world"); // 构造临时字符串 + 移动
2️⃣ emplace_back()
的原型和行为
template<typename... Args>
void emplace_back(Args&&... args);
直接使用构造函数参数在容器内构造对象,不会先创建临时对象。
🔧 示例:
std::vector<std::string> vec;
vec.emplace_back("hello"); // 直接在 vec 中构造 string,无需移动/拷贝
vec.emplace_back(5, 'a'); // 构造 string("aaaaa")
3️⃣ 性能对比示例(构造统计)
假设有如下类:
struct MyClass {
MyClass(int, int) { std::cout << "construct\n"; }
MyClass(const MyClass&) { std::cout << "copy\n"; }
MyClass(MyClass&&) { std::cout << "move\n"; }
};
使用 push_back
:
std::vector<MyClass> v;
v.push_back(MyClass(1, 2)); // construct + move(临时对象 -> 容器)
使用 emplace_back
:
v.emplace_back(1, 2); // construct(直接构造在容器中)
🔍 emplace_back()
省去了构造临时对象 + 移动的过程,更高效。
4️⃣ 表格总结
特性 | push_back |
emplace_back |
---|---|---|
需要预先构造对象 | ✅ 是的 | ❌ 直接在容器内构造 |
会调用拷贝/移动构造? | ✅ 经常 | ❌ 通常不会(构造就地) |
接受构造函数参数? | ❌ 不行 | ✅ 任意构造函数参数 |
使用语义 | 添加已有对象 | 构造并添加一个对象 |
推荐使用场景 | 简单类型或已有对象 | 构造复杂对象时优先 |
✅ 使用建议
- 如果你已经有一个对象(例如函数参数、变量),就用
push_back()
。 - 如果你想构造一个新对象并放进去,用
emplace_back()
更高效。 - 对于自定义类,推荐用
emplace_back
,避免不必要的移动/拷贝。
📌 小贴士
即使你写了:
vec.emplace_back(MyClass(1, 2));
也不会比 push_back 高效,因为你已经手动构造了临时对象,等效于 push_back。真正的优化写法是:
vec.emplace_back(1, 2); // ← 直接传构造参数才是关键