以下是对 vector
的 push_back
和 emplace_back
方法的详细解释:
一、push_back
方法
-
功能:
push_back
是std::vector
类的成员函数,用于在向量的末尾添加元素。- 当使用
push_back
时,会将元素的副本添加到向量的末尾。
-
使用示例:
#include <iostream>
#include <vector>
class MyClass {
public:
MyClass() {
std::cout << "Default constructor" << std::endl;
}
MyClass(const MyClass& other) {
std::cout << "Copy constructor" << std::endl;
}
MyClass(MyClass&& other) {
std::cout << "Move constructor" << std::endl;
}
~MyClass() {
std::cout << "Destructor" << std::endl;
}
};
int main() {
std::vector<MyClass> vec;
MyClass obj;
// 使用 push_back 添加元素
vec.push_back(obj);
return 0;
}
- 代码解释:
- 当调用
vec.push_back(obj);
时,会发生以下步骤:- 调用
MyClass
的复制构造函数,将obj
的副本添加到vec
的末尾。 - 如果
MyClass
支持移动语义(即提供了移动构造函数),编译器可能会调用移动构造函数进行优化,以避免不必要的复制。
- 调用
- 当调用
二、emplace_back
方法
-
功能:
emplace_back
也是std::vector
的成员函数,用于在向量的末尾直接构造元素。- 它通过
std::forward
将参数完美转发给元素的构造函数,避免了额外的复制或移动操作,在适当情况下可以提高性能。
-
使用示例:
#include <iostream>
#include <vector>
class MyClass {
public:
MyClass() {
std::cout << "Default constructor" << std::endl;
}
MyClass(const MyClass& other) {
std::cout << "Copy constructor" << std::endl;
}
MyClass(MyClass&& other) {
std::cout << "Move constructor" << std::endl;
}
~MyClass() {
std::cout << "Destructor" << std::endl;
}
MyClass(int x, int y) {
std::cout << "Custom constructor with arguments " << x << " and " << y << std::endl;
}
};
int main() {
std::vector<MyClass> vec;
// 使用 emplace_back 直接在向量末尾构造元素
vec.emplace_back(1, 2);
return 0;
}
- 代码解释:
- 当调用
vec.emplace_back(1, 2);
时,会发生以下步骤:- 直接在
vec
的末尾调用MyClass
的构造函数,使用1
和2
作为参数构造元素,而不是先创建对象,再复制或移动到向量中。
- 直接在
- 当调用
三、性能比较
push_back
与emplace_back
的性能对比:- 对于简单类型(如
int
、double
等),两者性能差异可能不明显,因为复制或移动的成本较低。 - 对于复杂类型(如自定义类),
emplace_back
可能更优,尤其是当类的复制或移动成本较高时。
- 对于简单类型(如
四、使用建议
-
何时使用
push_back
:- 当你已经有一个对象,并且想要将其副本添加到向量末尾时,可以使用
push_back
。
- 当你已经有一个对象,并且想要将其副本添加到向量末尾时,可以使用
-
何时使用
emplace_back
:- 当你想在向量末尾直接构造元素,并且元素的构造函数可以接受所需的参数时,使用
emplace_back
可以避免额外的复制或移动操作,提高性能。
- 当你想在向量末尾直接构造元素,并且元素的构造函数可以接受所需的参数时,使用
以下是一个综合使用 push_back
和 emplace_back
的示例:
#include <iostream>
#include <vector>
class MyClass {
public:
MyClass(int x) : data(x) {
std::cout << "Constructor with parameter: " << data << std::endl;
}
MyClass(const MyClass& other) : data(other.data) {
std::cout << "Copy constructor" << std::endl;
}
MyClass(MyClass&& other) : data(std::move(other.data)) {
std::cout << "Move constructor" << std::endl;
}
~MyClass() {
std::cout << "Destructor for " << data << std::endl;
}
int data;
};
int main() {
std::vector<MyClass> vec;
MyClass obj1(1);
// 使用 push_back 添加对象的副本
vec.push_back(obj1);
// 使用 emplace_back 直接在向量末尾构造元素
vec.emplace_back(2);
return 0;
}
总结
push_back
主要用于将现有对象的副本或移动对象添加到向量末尾,可能会调用复制或移动构造函数。emplace_back
用于在向量末尾直接构造元素,避免了额外的复制或移动操作,通过完美转发参数给元素的构造函数。- 在性能敏感的代码中,尤其是处理复杂类型时,优先考虑使用
emplace_back
可以提高性能。
需要注意的是,使用 emplace_back
时,需要确保元素的构造函数可以接受提供的参数,并且在某些情况下,编译器可能会自动优化 push_back
的性能,使其与 emplace_back
接近。