全面理解-STL容器中push_back与emplace_back的区别

在 C++ 的 std::vector 中,push_back 和 emplace_back 都是用于向容器末尾添加元素的成员函数,但它们的实现机制和使用场景有显著区别。

以下是两者的核心差异:


1. 参数传递方式

  • push_back
    接受一个已构造的对象作为参数(拷贝或移动):

    • 若传递左值(已存在的对象),会调用拷贝构造函数

    • 若传递右值(临时对象或 std::move 的结果),会调用移动构造函数(如果存在)。

    std::vector<std::string> vec;
    std::string s = "hello";
    
    vec.push_back(s);            // 拷贝构造(s 是左值)
    vec.push_back("world");      // 移动构造(临时对象是右值)
  • emplace_back
    直接通过参数包(variadic arguments)在容器内存中就地构造对象,避免临时对象的拷贝或移动。
    它使用**完美转发(perfect forwarding)**将参数传递给元素的构造函数。

    vec.emplace_back(3, 'a');    // 直接在 vector 内构造 std::string(3, 'a')

2. 性能差异

  • 对于需要拷贝/移动的类型(如非平凡类型 std::string、自定义类):

    • emplace_back 通常更高效,因为它跳过临时对象的构造

    • push_back 可能多一次拷贝/移动操作。

    class MyClass {
    public:
        MyClass(int a, int b) { /*...*/ }
        MyClass(const MyClass&) { std::cout << "Copy\n"; }
        MyClass(MyClass&&) { std::cout << "Move\n"; }
    };
    
    std::vector<MyClass> vec;
    
    vec.push_back(MyClass(1, 2));  // 1. 构造临时对象 -> 2. 移动构造到容器
    vec.emplace_back(1, 2);        // 直接构造在容器内(无拷贝/移动)
    
    //输出:
    Move  // push_back
    (无输出)  // emplace_back
  • 对于简单类型(如 intdouble):
    两者性能几乎无差别。


3. 使用场景

  • 优先使用 emplace_back
    当需要直接通过构造函数参数添加元素时,尤其是构造参数较多或对象较大时。

    vec.emplace_back("hello", 5);    // 直接调用 std::string(const char*, size_t)
  • 使用 push_back
    当已经有一个存在的对象需要添加到容器中(尤其是需要拷贝时)。

    std::string existing_str = "hello";
    vec.push_back(existing_str);     // 显式拷贝

4. 类型要求

  • push_back
    要求元素类型可拷贝构造移动构造

  • emplace_back
    要求元素类型有与参数包匹配的构造函数


5. 返回值(C++17 起)

  • push_back:无返回值(void)。

  • emplace_back:返回新插入元素的引用reference)。
    可链式调用:

    vec.emplace_back(1, 2).doSomething();

6. 显式构造函数调用

emplace_back 可能因参数隐式转换导致意外行为,需注意显式构造函数:

class Wrapper {
public:
    explicit Wrapper(int x) { /*...*/ }  // explicit 构造函数
};

std::vector<Wrapper> vec;
vec.push_back(10);        // ❌ 错误:不能隐式转换 int 到 Wrapper
vec.push_back(Wrapper(10));  // ✅ 需显式构造
vec.emplace_back(10);     // ✅ 合法:直接调用 Wrapper(int)

总结

特性push_backemplace_back
参数类型对象(左值/右值)构造参数包
临时对象构造需要(可能触发拷贝/移动)不需要(直接就地构造)
性能(非平凡类型)较低(多一次拷贝/移动)较高
适用场景已有对象需要拷贝/移动时直接通过参数构造新对象时
返回值void新元素的引用(C++17 起)

建议

  • 默认优先使用 emplace_back,尤其是构造对象时代码更简洁且性能更优。

  • 若需强制拷贝或移动语义,或处理显式构造函数时,使用 push_back

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

HL_LOVE_C

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值