STL容器的emplace操作
emplace是c++11引入的成员,作用是优化存储类的vector,deque,list容器
c.emplace_back(构造函数的参数) //向尾部添加一个对象,参数为类的构造函数的参数
c.emplace_front(构造函数的参数)
c.emplace(iteator,构造函数的参数) //向迭代器参数前添加一个对象
例如:
我们新创建一个存储Human类的vector
int main()
{
vector<Human> v;
system("pause");
return 0;
}
//Human头文件
class Human
{
public:
Human(string name = "",int age = 0);
Human(const Human& h);
~Human();
friend ostream& operator<<(ostream& os, Human h);
private:
string name;
int age;
};
ostream& operator<<(ostream& os, Human h);
#include "Human.h"
Human::Human(string name,int age) {
this->name = name;
this->age = age;
cout << "构造函数" << endl;
}
Human::Human(const Human& h)
{
name = h.name;
age = h.age;
cout << "拷贝构造函数" << endl;
}
Human::~Human()
{
cout << "析构函数" << endl;
}
ostream& operator<<(ostream& os, Human h) {
os << h.name << ": " << h.age;
return os;
}
此时我们要向v内部添加对象的话,先看push_back操作:
int main()
{
vector<Human> v;
//此时会先调用Human的构造函数,创建一个临时的Human,然后v进行拷贝构造函数存进v中
//然后调用析构函数销毁push_back中临时创建的Human
v.push_back(Human());
//最后main函数结束,调用v内部的Human的析构函数销毁
system("pause");
return 0;
}
虽然用push_back不会出现任何问题,但是我们会发现,这种方式实际上创建了两个Human,造成了资源上的浪费,此时我们就可以使用emplace方法
int main()
{
vector<Human> v;
//emplace_back()的参数为所存储的类的构造函数的参数,类不需要参数就可以不写
//v.emplace_back("xxx",20);
v.emplace_back();
//此时只创建了一次Human
system("pause");
return 0;
}
值得注意的点:
如果是vector,像下面这样运行的话,会出现不一样的情况
int main()
{
vector<Human> v;
v.emplace_back();
v.emplace_back();
system("pause");
return 0;
}
照上面的想法来看,此时应该只会打印两个构造函数,可是结果却与我们想象的不同
这是因为vector的特殊性质: vector是一个变长的数组,第一次正常执行一次构造函数,但是接下来要再次添加的时候,原本数组的长度不够了,所以它会申请一块更大的内存,将原来的内容拷贝到新的内存中,再将新添加的对象放到末尾
如果我们将vector改为list的话就不会有此问题,因为list执行添加操作不用执行上述操作,其他容器类似
拓展vector的capacity()操作
由于vector是一个变长的数组,如果每次添加对象到vector内部,那么每次都需要重新分配一次空间,会十分麻烦,所以vector在创建或添加的时候,会预先分配比当前大的空间,可以使用capacity()查看预分配的大小
int main(){
//以简单的int的vector为例
//创建有10个0的vector
vector<int> v2(10,0);
//capacity()查看预分配空间的大小
//size()查看实际占用空间的大小
cout << "v2.capacity() 长度为: " << v2.capacity() << endl;
cout << "v2.size() 长度为: " << v2.size() << endl;
v2.push_back(1);
cout << "添加对象后" << endl;
cout << "v2.capacity() 长度为: " << v2.capacity() << endl;
cout << "v2.size() 长度为: " << v2.size() << endl;
}
我们可以看到,在创建之后,预分配和实际的大小都是10个int,添加一个对象之后,实际长度加1,而为了让之后添加元素的操作变得更快,预先分配了15个int大小的长度(正是因为此特性,有些时候vector的添加速度甚至比list快)