在C++中,有两种方法向vector中添加元素:push_back()
和emplace_back
。在这篇文章中,主要讨论他们之间的区别。
push_back()
push_back()通常用于向容器vector的尾部添加一个元素。由于vector的大小是动态变化的,所以向其插入一个元素后,它的容量也增加1。
Program 1:
// C++ program to demonstrate the
// push_back() method
#include <iostream>
#include <vector>
using namespace std;
// Class
class GFG {
public:
int x;
// Parameterized Constructor
GFG(int x)
: x(x)
{
cout << "Constructor=>"
<< "x:" << x << endl;
}
// Copy Constructor
GFG(const GFG& GFG)
: x(GFG.x)
{
cout << "Copied=>"
<< "x:" << x << endl;
}
~GFG()
{
cout << "destructor=>"
<< "x:" << x << endl;
}
};
// Driver Code
int main()
{
// Vector of object of GFG class
// is created
vector<GFG> vertices;
cout << "length of vertices:" << vertices.size()
<< endl;
// Inserting elements in the object
// created using push_back() method
cout << endl;
// Custom input entries
vertices.push_back(GFG(1));
cout << endl;
vertices.push_back(GFG(11));
cout << endl;
vertices.push_back(GFG(21));
cout << endl;
return 0;
}
Output
length of vertices:0
Constructor=>x:1
Copied=>x:1
destructor=>x:1
Constructor=>x:11
Copied=>x:11
Copied=>x:1
destructor=>x:1
destructor=>x:11
Constructor=>x:21
Copied=>x:21
Copied=>x:1
Copied=>x:11
destructor=>x:1
destructor=>x:11
destructor=>x:21
destructor=>x:1
destructor=>x:11
destructor=>x:21
解释:
- 每次向vector中追加一个元素,CPP会创建一个新的vector,并且把新的要添加的元素和“旧vector”中的所有元素复制到新的vector中。
- 在main函数中,首先创建一个可以容纳GFG类的vector(vector1),它的大小是0。当使用
GFG(int)
作为参数传递到vector中,会首先调用GFG的构造函数,构造一个GFG的对象,然后调用拷贝构造函数,把这个GFG对象复制到vector中,所以会输出一次“Copied”。 - 当向vector中添加第二个元素,一个新的vector(vector2)会被创建,并且GFG(11)会被复制到vector2中。并且,旧vector(vector1)中的所有元素都会被拷贝到新vector(vector2)中。vector1中有1个元素,新添加了一个元素,所以会输出两次“Copied”。
- 同样的,当第3个GFG对象被创建,并且添加到vector中时,会创建一个新的vector(vector3)。新添加的元素会被复制到vector3中,vector2中的两个元素也会被复制到vector3中,调用了3次拷贝构造函数,所以出现了3次“Copied”。
- 但是,如果vector的大小是固定的,每次添加一个新元素的时候,只会输出一次“Copied”。这是因为所需大小一开始就被声明了,后面不会发生再次复制元素的情况。
注意:
“Copied”出现的次数并不是每添加一个元素就多出现一次,Program 1中碰巧了。只有在vector需要扩容的时候(即旧vector中的元素需要复制到新vector中时)才会出现多次。在不需要扩容的时候,“Copied”只出现一次,这一次就是用来把新元素添加到vector中。
Program 2:
拷贝元素带来的代价是很大的,下面是对上面代码的一种优化,拷贝的次数明显减少:
// C++ Program to optimize the usage
// of C++ Vectors to reduce the cost
// of copying elements with the
// reserve() method
#include <iostream>
#include <vector>
using namespace std;
// Class
class GFG {
public:
float x, y;
// Parameterized Constructor
GFG(float x, float y)
: x(x), y(y)
{
}
// Copy Constructor
GFG(const GFG& GFG)
: x(GFG.x), y(GFG.y)
{
cout << "Copied" << endl;
}
};
// Driver Code
int main()
{
// Create object of vector in
// the main() method
vector<GFG> vertices;
// Reserve three elements using
// reserve()
vertices.reserve(3);
// Add elements to the vector
// object
vertices.push_back(GFG(1, 2));
cout << endl;
vertices.push_back(GFG(4, 5));
cout << endl;
vertices.push_back(GFG(7, 8));
cout << endl;
return 0;
}
Output:
Copied
Copied
Copied
emplace_back()
push_back()是先使用构造函数创建一个对象,然后使用拷贝构造函数把这个对象传递到vector中。emplace_back()不使用拷贝构造函数,直接将构造函数所需的参数传递过去,构建一个新的对象出来,填充到vector尾部。
Program 3:
// C++ Program to illustrate the high
// cost of copying the elements in
// vector in STL
#include <iostream>
#include <vector>
using namespace std;
// Class
class GFG {
public:
float x, y;
// Parameterized Constructor
GFG(float x, float y)
: x(x), y(y)
{
}
// Copy Constructor
GFG(const GFG& GFG)
: x(GFG.x), y(GFG.y)
{
cout << "Copied" << endl;
}
};
// Driver Code
int main()
{
// Create an object of vector
// class object
vector<GFG> vertices;
// Reserve the elements in the
// vector using reserve() method
vertices.reserve(3);
// Add element to vector object
// using emplace_back() method
vertices.emplace_back(1, 2);
cout << endl;
vertices.emplace_back(4, 5);
cout << endl;
vertices.emplace_back(7, 8);
cout << endl;
return 0;
}
Output:
以上的代码中没有调用一次拷贝构造函数,所以什么都没有输出。
总结
在添加GFG这种自定义类型时:
- push_back需要先调用构造函数,在调用拷贝构造函数,在调用析构函数。
- emplace_back只需要调用构造函数就可以了。
所以,emplace_back在这种情况下效率更高。