面试题:C++ 中 vector 的 push_back 和 emplace_back 有什么区别?

push_back 和 emplace_back 是 C++ 中 std::vector 的两个成员函数,用于向容器末尾添加元素。它们的核心区别在于如何构造元素以及性能优化


1. push_back

  • 功能
    • 将元素添加到 vector 的末尾。
    • 如果传递的是一个对象,push_back 会调用该对象的拷贝构造函数移动构造函数
    • 如果传递的是临时对象(右值),push_back 会调用移动构造函数(如果存在)。
  • 性能
    • 如果传递的是左值对象,push_back 会调用拷贝构造函数,可能导致额外的性能开销。
    • 如果传递的是右值对象,push_back 会调用移动构造函数,性能较好。

2. emplace_back

  • 功能
    • 直接在 vector 的末尾就地构造元素,避免了不必要的拷贝或移动操作。
    • 它通过传递的参数直接调用元素的构造函数。
  • 性能
    • emplace_back 直接在容器中构造对象,避免了临时对象的创建和拷贝/移动操作,性能通常优于 push_back

3. 区别对比

特性push_backemplace_back
参数类型接受对象(左值或右值)接受构造对象所需的参数
构造方式调用拷贝构造函数或移动构造函数直接在容器中构造对象
性能可能涉及临时对象的拷贝或移动避免临时对象,性能更优
适用场景适合已经构造好的对象适合直接传递构造参数

4. 代码示例对比

使用 push_back

#include <vector>
#include <string>

int main() {
    std::vector<std::string> vec;
    std::string str = "Hello";
    vec.push_back(str);          // 调用拷贝构造函数
    vec.push_back(std::move(str)); // 调用移动构造函数
    return 0;
}

使用 emplace_back

#include <vector>
#include <string>

int main() {
    std::vector<std::string> vec;
    vec.emplace_back("Hello");  // 直接调用 std::string 的构造函数
    return 0;
}

5. 性能优化示例

假设有一个类 MyClass,其构造函数接受多个参数:

class MyClass {
public:
    MyClass(int a, int b, int c) {
        std::cout << "MyClass constructed" << std::endl;
    }
};
  • 使用 push_back
    std::vector<MyClass> vec;
    vec.push_back(MyClass(1, 2, 3));  // 先构造临时对象,再移动
  • 使用 emplace_back
    std::vector<MyClass> vec;
    vec.emplace_back(1, 2, 3);  // 直接在容器中构造对象

emplace_back 避免了临时对象的构造和移动,性能更优。


6. 总结

  • push_back
    • 接受一个对象(左值或右值),调用拷贝构造函数或移动构造函数。
    • 适合已经构造好的对象。
  • emplace_back
    • 接受构造对象所需的参数,直接在容器中构造对象。
    • 性能更优,适合直接传递构造参数。

在现代 C++ 中,优先使用 emplace_back,尤其是当对象的构造参数已知时,可以避免不必要的拷贝或移动操作。

THE END
点赞14 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容