vector的push_back和emplace_back有什么区别?
参考回答
push_back
和 emplace_back
都是用来向 std::vector
添加新元素的函数,主要区别在于:
push_back
:需要一个已构造的对象,将其拷贝(或移动)到vector
中。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_back
和 emplace_back
的主要区别在于对象的创建方式:
– push_back
使用已存在的对象,可能会涉及拷贝或移动操作。
– emplace_back
直接在容器中原地构造对象,避免额外开销。
在需要动态创建对象的场景下,emplace_back
通常更高效。合理选择两者,可以提高代码的性能和可读性。