C++STL之push_back()和emplace_back

🆚 一句话区别

push_back()emplace_back() 都是 std::vectorstd::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); // ← 直接传构造参数才是关键

posted @ 2025-05-09 17:05  江海余生  阅读(61)  评论(0)    收藏  举报