vector的push_back和emplace_back有什么区别?

参考回答

push_backemplace_back 都是用来向 std::vector 添加新元素的函数,主要区别在于:

  1. push_back:需要一个已构造的对象,将其拷贝(或移动)到 vector 中。
  2. emplace_back:直接在 vector 的存储空间中原地构造对象,避免了额外的拷贝或移动操作。

简单来说:
– 如果已经有一个现成的对象,使用 push_back
– 如果需要传递构造参数创建对象,使用 emplace_back


详细讲解与拓展

1. push_back 的工作机制

push_back 将一个现成的对象添加到 vector 中:
– 如果对象支持移动语义,调用其移动构造函数。
– 否则调用其拷贝构造函数。

示例:

#include <vector>
#include <iostream>
using namespace std;

class MyClass {
public:
    MyClass(int x) { cout << "Constructor: " << x << endl; }
    MyClass(const MyClass& other) { cout << "Copy Constructor" << endl; }
    MyClass(MyClass&& other) noexcept { cout << "Move Constructor" << endl; }
};

int main() {
    vector<MyClass> v;
    MyClass obj(10);
    v.push_back(obj);  // 调用拷贝构造函数
    v.push_back(std::move(obj));  // 调用移动构造函数
    return 0;
}

输出:

Constructor: 10
Copy Constructor
Move Constructor

2. emplace_back 的工作机制

emplace_back 将对象的构造过程直接嵌入到 vector 的存储空间中,无需临时对象:
– 使用提供的参数,直接调用对象的构造函数。

示例:

#include <vector>
#include <iostream>
using namespace std;

class MyClass {
public:
    MyClass(int x) { cout << "Constructor: " << x << endl; }
    MyClass(const MyClass& other) { cout << "Copy Constructor" << endl; }
    MyClass(MyClass&& other) noexcept { cout << "Move Constructor" << endl; }
};

int main() {
    vector<MyClass> v;
    v.emplace_back(10);  // 直接在 vector 中调用构造函数
    return 0;
}

输出:

Constructor: 10

可以看到,emplace_back 直接调用了构造函数,没有拷贝或移动操作。


3. 性能比较

  • push_back 需要传递一个现成的对象,可能会涉及拷贝或移动操作,效率较低。
  • emplace_back 直接原地构造对象,省去了构造临时对象的开销,效率更高。

适用场景:
– 如果直接构造对象,优先使用 emplace_back
– 如果已有现成的对象(如变量或函数返回值),使用 push_back


4. 示例对比

以下代码展示了两者的性能差异:

#include <vector>
#include <iostream>
using namespace std;

class MyClass {
public:
    MyClass(int x, int y) { cout << "Constructor: " << x << ", " << y << endl; }
    MyClass(const MyClass& other) { cout << "Copy Constructor" << endl; }
    MyClass(MyClass&& other) noexcept { cout << "Move Constructor" << endl; }
};

int main() {
    vector<MyClass> v1, v2;

    cout << "Using push_back:" << endl;
    MyClass obj(1, 2);
    v1.push_back(obj);  // 调用拷贝构造
    v1.push_back(std::move(obj));  // 调用移动构造

    cout << "\nUsing emplace_back:" << endl;
    v2.emplace_back(1, 2);  // 直接原地构造

    return 0;
}

输出:

Using push_back:
Constructor: 1, 2
Copy Constructor
Move Constructor

Using emplace_back:
Constructor: 1, 2

可以看到,emplace_back 避免了拷贝和移动操作。


5. 注意事项

  • 如果使用 emplace_back,传递的参数必须匹配对象的构造函数,否则会导致编译错误。
  • 在性能敏感的代码中,优先考虑使用 emplace_back

总结

push_backemplace_back 的主要区别在于对象的创建方式:
push_back 使用已存在的对象,可能会涉及拷贝或移动操作。
emplace_back 直接在容器中原地构造对象,避免额外开销。

在需要动态创建对象的场景下,emplace_back 通常更高效。合理选择两者,可以提高代码的性能和可读性。

发表评论

后才能评论