在 C++ 标准库中,std::vector
是一种动态数组,它允许在运行时动态地增加或减少元素。在添加元素时,std::vector
提供了两种常用的方法:push_back()
和 emplace_back()
。尽管两者在表面上看起来相似,但它们在底层实现和使用场景上有所不同。
push_back()
push_back()
方法用于将一个元素添加到 vector
的末尾。这个方法接受一个参数,该参数是你要添加到 vector
中的元素的副本。因此,push_back()
会涉及到复制或移动构造函数的调用(取决于你传递给它的参数类型)。
#include <iostream>
#include <vector>
#include <string>
class MyClass {
public:
MyClass(const std::string& name) : name_(name) {
std::cout << "MyClass(" << name_ << ") constructed\n";
}
MyClass(const MyClass& other) : name_(other.name_) {
std::cout << "MyClass(" << name_ << ") copy constructed\n";
}
MyClass(MyClass&& other) noexcept : name_(std::move(other.name_)) {
std::cout << "MyClass(" << name_ << ") move constructed\n";
}
~MyClass() {
std::cout << "MyClass(" << name_ << ") destructed\n";
}
private:
std::string name_;
};
int main() {
std::vector<MyClass> vec;
MyClass obj("example");
vec.push_back(obj); // 调用复制构造函数
return 0;
}
在上述代码中,push_back(obj)
会导致 obj
的复制构造函数被调用,因为 push_back()
需要一个元素的副本。
emplace_back()
emplace_back()
方法也是用于将元素添加到 vector
的末尾,但它是通过直接在 vector
的内存位置构造元素来实现的。这意味着你可以避免额外的复制或移动操作,特别是对于大型对象或那些复制/移动代价较高的对象,使用 emplace_back()
可以带来性能上的优势。
emplace_back()
接受与元素构造函数相同的参数,并直接在 vector
的内存位置调用元素的构造函数。
#include <iostream>
#include <vector>
#include <string>
class MyClass {
public:
MyClass(const std::string& name) : name_(name) {
std::cout << "MyClass(" << name_ << ") constructed\n";
}
~MyClass() {
std::cout << "MyClass(" << name_ << ") destructed\n";
}
private:
std::string name_;
};
int main() {
std::vector<MyClass> vec;
vec.emplace_back("example"); // 直接在 vector 的内存位置构造元素
return 0;
}
在这个例子中,emplace_back("example")
直接在 vec
的内存位置构造了一个 MyClass
对象,没有涉及到复制或移动构造函数。
使用场景
**
push_back()
**:当你已经有一个现成的对象,并且希望将其添加到 vector
中时,可以使用push_back()
。当对象的复制或移动代价较低时, push_back()
是一个不错的选择。**
emplace_back()
**:当你需要构造一个对象并将其直接添加到 vector
中时,使用emplace_back()
可以避免不必要的复制或移动操作。当对象的复制或移动代价较高时, emplace_back()
通常会提供更好的性能。当你使用复杂的类型(如包含智能指针或大型数据结构的类型)时, emplace_back()
可以帮助你避免不必要的临时对象创建和销毁。
总结
push_back()
需要一个对象的副本,会调用复制或移动构造函数。emplace_back()
直接在vector
的内存位置构造对象,避免了额外的复制或移动操作。根据你的具体需求(如对象的构造复杂度、复制/移动代价等),选择适当的方法来添加元素到 vector
中。
通过理解这两种方法的区别和使用场景,你可以编写出更高效、更简洁的 C++ 代码。