C++11新特性(4):emplace() 和 insert()

98用太久,学习下11,根据网上资料的知识总结。

1. 区别

   1.1 insert() 一次可以插入多个元素,而emplace() 每次只能插入一个元素。

   1.2 当插入对象时,emplace()的效率更高。

    因为emplace() 在插入元素时,是在容器的指定位置直接构造元素,而不是先单独生成,再将其复制(或移动)到容器中。因此,建议优先使用 emplace()。    

2. 以std::vector为例

#include 
class Test
{
public:
	Test(int a) { cout << "Test(int)" << endl; }//构造函数
	Test(const Test& a) { cout << "Test(const Test&)" << endl; }//拷贝构造函数
	Test(const Test&& a) { cout << "Test(const Test&&)" << endl; }//移动构造函数
	Test& operator = (const Test &a) { cout << "=(const Test&)" << endl; return *this; }
	~Test() { cout << "~Test()" << endl; }
};

int main()
{
	vector vecObj;
	{
		vecObj.reserve(10);//只开辟空间,没有构建对象
		cout << "========insert================" << endl;
		vecObj.insert(vecObj.end(), 100);
		cout << "========push_back=============" << endl;
		vecObj.push_back(200);
		cout << "========emplace===============" << endl;
		vecObj.emplace(vecObj.end(), 300);
		cout << "========emplace_back==========" << endl;
		vecObj.emplace_back(400);
		cout << "=====================" << endl;
	}
	system("pause");
	return 0;
}

    运行结果:

C++11新特性(4):emplace() 和 insert()_第1张图片

 由结果可以看出emplace()/emplace_back()只调用了一次构造函数,而insert()/push_back()多调用了一次移动构造函数(或拷贝构造函数)和析构函数。

注意:

a. 当拷贝构造函数和移动构造函数同时存在时,insert() 会优先调用移动构造函数。

b. vecObj.reserve(10); 预先开辟空间很重要,影响性能。

修改代码(注释掉移动构造函数和reserve调用):

#include 
class Test
{
public:
	Test(int a) { cout << "Test(int)" << endl; }//构造函数
	Test(const Test& a) { cout << "Test(const Test&)" << endl; }//拷贝构造函数
	//Test(const Test&& a) { cout << "Test(const Test&&)" << endl; }//移动构造函数
	Test& operator = (const Test &a) { cout << "=(const Test&)" << endl; return *this; }
	~Test() { cout << "~Test()" << endl; }
};

int main()
{
	vector vecObj;
	{
		//vecObj.reserve(10);//只开辟空间,没有构建对象
		cout << "========insert================" << endl;
		vecObj.insert(vecObj.end(), 100);
		cout << "========push_back=============" << endl;
		vecObj.push_back(200);
		cout << "========emplace===============" << endl;
		vecObj.emplace(vecObj.end(), 300);
		cout << "========emplace_back==========" << endl;
		vecObj.emplace_back(400);
		cout << "=====================" << endl;
	}
	system("pause");
	return 0;
}

运行结果:

C++11新特性(4):emplace() 和 insert()_第2张图片

  由结果可以看出如果没有调用reserve(),每次插入新元素时(改变vector大小),都会多次调用拷贝构造(或移动构造)函数和析构函数。调用次数由vector里原有元素个数决定,个数越多,越影响性能。

3. 以std::map为例

#include 
class Test
{
	int v;
public:
	Test(int i):v(i) { cout << "Test(int)" << endl; }//构造函数
	Test(const Test& a):v(a.v) { cout << "Test(const Test&)" << endl; }//拷贝构造函数
	Test(const Test&& a):v(a.v) { cout << "Test(const Test&&)" << endl; }//移动构造函数
	Test& operator = (const Test &a) { v = a.v; cout << "=(const Test&)" << endl; return *this; }
	~Test() { cout << "~Test()" << endl; }
	int Get() { return v; }
};

int main()
{
	std::map mapObj;
	{
		cout << "========insert1================" << endl;
		mapObj.insert(make_pair("1",100));
		cout << "========insert2================" << endl;
		mapObj.insert({ "2", 200 });
		cout << "========emplace===============" << endl;
		pair::iterator, bool> ret = mapObj.emplace("3", 300);
		cout << "emplace result:" <first<< endl;
		cout << "========emplace_hint==========" << endl;
		map::iterator it = mapObj.emplace_hint(mapObj.end(),"4", 400);
		cout << "emplace_hint result:"<< "key is " << it->first << endl;
		cout << "=====================" << endl;
	}
	for (auto& v : mapObj) {
		cout << v.first << " " << v.second.Get() << endl;
	}

	system("pause");
	return 0;
}

运行结果:

C++11新特性(4):emplace() 和 insert()_第3张图片

 由结果可以看出第二个insert方法多调用了一次移动构造函数(或拷贝构造函数)和析构函数。

3.1 map的emplace()的返回值为 pair 类型值,其包含一个迭代器和一个 bool 类型值。

      添加新键值对成功时,返回的迭代器指向新添加的键值对,bool 值为 True;失败时,说明容器中本就包含一个键相等的键值对,此时返回的迭代器指向的就是容器中键相同的这个键值对,bool 值为 False。

3.2 map的emplace_hint()的返回值仅是一个迭代器,而不再是 pair 类型变量。

      添加新键值对成功时,返回的迭代器指向新添加的键值对;反之,如果添加失败,该迭代器指向的是容器中和要添加键值对键相同的那个键值对。

      另外,emplace_hint()方法需要传递一个迭代器作为第一个参数,该迭代器表明将新键值对添加到容器中的位置。需要注意的是,新键值对添加到容器中的位置,并不是此迭代器说了算,最终仍取决于该键值对的键的值。

你可能感兴趣的:(C++,c++)