C++11容器中新增加的emplace相关函数的使用

C++11中,针对顺序容器(如vector、deque、list),新标准引入了三个新成员:emplace_front、emplace和emplace_back,这些操作构造而不是拷贝元素。这些操作分别对应push_front、insert和push_back,允许我们将元素放置在容器头部、一个指定位置之前或容器尾部。

当调用push或insert成员函数时,我们将元素类型的对象传递给它们,这些对象被拷贝到容器中而当我们调用一个emplace成员函数时,则是将参数传递给元素类型的构造函数。emplace成员使用这些参数在容器管理的内存空间中直接构造元素。

emplace函数的参数根据元素类型而变化,参数必须与元素类型的构造函数相匹配。emplace函数在容器中直接构造元素。传递给emplace函数的参数必须与元素类型的构造函数相匹配。

其它容器中,std::forward_list中的emplace_after、emplace_front函数,std::map/std::multimap中的emplace、emplace_hint函数,std::set/std::multiset中的emplace、emplace_hint,std::stack中的emplace函数,等emplace相似函数操作也均是构造而不是拷贝元素。

emplace相关函数可以减少内存拷贝和移动。当插入rvalue,它节约了一次move构造,当插入lvalue,它节约了一次copy构造。

下面是从其他文章中copy的测试代码,详细内容介绍可以参考对应的reference:

#include "emplace.hpp"
#include <iostream>
#include <vector>
#include <string>
#include <map>
#include <tuple>
#include <utility>

namespace emplace_ {

/
// reference: http://www.cplusplus.com/reference/vector/vector/emplace_back/
int test_emplace_1()
{
{
	/*
		template <class... Args>
		void emplace_back (Args&&... args);
	*/
	std::vector<int> myvector = { 10, 20, 30 };

	myvector.emplace_back(100);
	myvector.emplace_back(200);

	std::cout << "myvector contains:";
	for (auto& x : myvector)
		std::cout << ' ' << x;
	std::cout << '\n';
}

{
	/*
		template <class... Args>
		iterator emplace (const_iterator position, Args&&... args);
	*/
	std::vector<int> myvector = { 10, 20, 30 };

	auto it = myvector.emplace(myvector.begin() + 1, 100);
	myvector.emplace(it, 200);
	myvector.emplace(myvector.end(), 300);

	std::cout << "myvector contains:";
	for (auto& x : myvector)
		std::cout << ' ' << x;
	std::cout << '\n';
}

	return 0;
}

///
// reference: http://en.cppreference.com/w/cpp/container/vector/emplace_back
namespace {
struct President {
	std::string name;
	std::string country;
	int year;

	President(std::string p_name, std::string p_country, int p_year)
		: name(std::move(p_name)), country(std::move(p_country)), year(p_year)
	{
		std::cout << "I am being constructed.\n";
	}
	President(President&& other)
		: name(std::move(other.name)), country(std::move(other.country)), year(other.year)
	{
		std::cout << "I am being moved.\n";
	}
	President& operator=(const President& other) = default;
};
}

int test_emplace_2()
{
	/*
		The following code uses emplace_back to append an object of type President to a std::vector.
		It demonstrates how emplace_back forwards parameters to the President constructor and shows
		how using emplace_back avoids the extra copy or move operation required when using push_back.
	*/
	std::vector<President> elections;
	std::cout << "emplace_back:\n";
	elections.emplace_back("Nelson Mandela", "South Africa", 1994);

	std::vector<President> reElections;
	std::cout << "\npush_back:\n";
	reElections.push_back(President("Franklin Delano Roosevelt", "the USA", 1936));

	std::cout << "\nContents:\n";
	for (President const& president : elections) {
		std::cout << president.name << " was elected president of "
			<< president.country << " in " << president.year << ".\n";
	}
	for (President const& president : reElections) {
		std::cout << president.name << " was re-elected president of "
			<< president.country << " in " << president.year << ".\n";
	}

	return 0;
}


// reference: https://stackoverflow.com/questions/4303513/push-back-vs-emplace-back
int test_emplace_3()
{
	/*
		template <class... Args>
		pair<iterator,bool> emplace (Args&&... args);
	*/
	typedef std::tuple<int, double, std::string> Complicated;

	std::map<int, Complicated> m;
	int anInt = 4;
	double aDouble = 5.0;
	std::string aString = "C++";

	// cross your finger so that the optimizer is really good
	//m.insert(/*std::make_pair*/std::pair<int, Complicated>(4, Complicated(anInt, aDouble, aString)));
	m.insert(std::make_pair(4, Complicated(anInt, aDouble, aString)));

	// should be easier for the optimizer
	m.emplace(6, Complicated(anInt, aDouble, aString));
	/*
		std::piecewise_construct: This constant value is passed as the first argument to construct a pair object
		to select the constructor form that constructs its members in place by forwarding the elements of two
		tuple objects to their respective constructor.
	*/
	m.emplace(std::piecewise_construct, std::make_tuple(8), std::make_tuple(anInt, aDouble, aString));

	return 0;
}

//
// reference: https://corecplusplustutorial.com/difference-between-emplace_back-and-push_back-function/
namespace {
class Dat {
	int i;
	std::string ss;
	char c;

public:
	Dat(int ii, std::string s, char cc) :i(ii), ss(s), c(cc) { }

	~Dat() { }
};
}

int test_emplace_4()
{
	std::vector<Dat> vec;
	vec.reserve(3);

	vec.push_back(Dat(89, "New", 'G')); // efficiency lesser
	//vec.push_back(678, "Newer", 'O'); // error,push_back can’t accept three arguments
	vec.emplace_back(890, "Newest", 'D'); // work fine, efficiency is also more

	return 0;
}

} // namespace emplace_

GitHubhttps://github.com/fengbingchun/Messy_Test  

### 回答1: 在 C++ 中,以下容器可以使用 `emplace_back` 函数: 1. `std::vector` 2. `std::deque` 3. `std::list` 4. `std::forward_list` 5. `std::set` 6. `std::multiset` 7. `std::map` 8. `std::multimap` 9. `std::unordered_set` 10. `std::unordered_multiset` 11. `std::unordered_map` 12. `std::unordered_multimap` `emplace_back` 的作用是在容器的尾部插入一个元素,并利用该元素的构造函数直接在容器中构造该元素,避免了一次不必要的拷贝构造,从而提高了效率。 ### 回答2: 在C++中,有以下几种容器可以使用emplace_back()函数: 1. 向量(vector):向量是一种动态数组,可以使用emplace_back()函数在向量的末尾添加元素。emplace_back()函数会将指定参数作为元素的构造函数的参数,直接在向量的末尾构造一个新元素。 2. 列表(list):列表是一种双向链表,可以使用emplace_back()函数在列表的末尾添加元素。emplace_back()函数会将指定参数作为元素的构造函数的参数,直接在列表的末尾构造一个新元素。 3. 队列(queue):队列是一种先进先出的容器,可以使用emplace_back()函数在队列的末尾添加元素。emplace_back()函数会将指定参数作为元素的构造函数的参数,直接在队列的末尾构造一个新元素。 4. 双端队列(deque):双端队列是一种允许在两端进行插入和删除操作的容器,可以使用emplace_back()函数在双端队列的末尾添加元素。emplace_back()函数会将指定参数作为元素的构造函数的参数,直接在双端队列的末尾构造一个新元素。 总之,无论是动态数组、链表还是队列,只要支持在容器末尾添加元素的操作,都可以使用emplace_back()函数来构造和插入新元素。该函数可以避免额外的拷贝开销,效率更高。 ### 回答3: 在C++中,可以使用emplace_back函数来在容器的末尾直接构造并插入元素。emplace_back函数适用于以下几种容器: 1. vector:vector是一种动态数组,可以使用emplace_back来构造并插入元素。例如: ```cpp std::vector<int> vec; vec.emplace_back(1); // 构造并插入1 vec.emplace_back(2); // 构造并插入2 ``` 2. deque:deque是一种双端队列,也可以使用emplace_back函数来构造并插入元素。例如: ```cpp std::deque<int> dq; dq.emplace_back(1); // 构造并插入1 dq.emplace_back(2); // 构造并插入2 ``` 3. list:list是一种双向链表,同样可以使用emplace_back函数来构造并插入元素。例如: ```cpp std::list<int> lst; lst.emplace_back(1); // 构造并插入1 lst.emplace_back(2); // 构造并插入2 ``` 4. forward_list:forward_list是一种单向链表,也可以使用emplace_back函数来构造并插入元素。例如: ```cpp std::forward_list<int> flst; flst.emplace_back(1); // 构造并插入1 flst.emplace_back(2); // 构造并插入2 ``` 5. stack:stack是一种后进先出(LIFO)的容器适配器,它底层可以选择使用deque或list来实现。但是由于stack的特性,其只提供push和pop函数,不支持直接构造并插入元素。 总结起来,可以使用emplace_back函数来在vector、deque、list和forward_list这些容器的末尾直接构造并插入元素,而不需要先构造元素再插入。但要注意,对于stack这种容器适配器,不支持emplace_back函数
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值