天天看点

STL容器的emplace操作STL容器的emplace操作

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;
}
           
STL容器的emplace操作STL容器的emplace操作

虽然用push_back不会出现任何问题,但是我们会发现,这种方式实际上创建了两个Human,造成了资源上的浪费,此时我们就可以使用emplace方法

int main()
{
    vector<Human> v;
    //emplace_back()的参数为所存储的类的构造函数的参数,类不需要参数就可以不写
    //v.emplace_back("xxx",20);
    v.emplace_back();
    //此时只创建了一次Human
    system("pause");
    return 0;
}
           
STL容器的emplace操作STL容器的emplace操作

值得注意的点:

如果是vector,像下面这样运行的话,会出现不一样的情况

int main()
{
    vector<Human> v;
    v.emplace_back();
    v.emplace_back();
    system("pause");
    return 0;
}
           
STL容器的emplace操作STL容器的emplace操作

照上面的想法来看,此时应该只会打印两个构造函数,可是结果却与我们想象的不同

这是因为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;
}
           
STL容器的emplace操作STL容器的emplace操作

我们可以看到,在创建之后,预分配和实际的大小都是10个int,添加一个对象之后,实际长度加1,而为了让之后添加元素的操作变得更快,预先分配了15个int大小的长度(正是因为此特性,有些时候vector的添加速度甚至比list快)

继续阅读