容器中的emplace

C++11 为容器新增了 emplace 函数,它可以“就地”构造,减少了构造后再拷贝、转移的成本,提高了效率,而且用起来也很方便。
以vector为例,vector中提供了push_backemplace_back两个方法,对于直接插入对象的情形,两者没有任何区别:

class Test
{
public:
	Test(int) { cout << "Test(int)" << endl; }
	Test(int, int) { cout << "Test(int, int)" << endl; }
	Test(const Test&) { cout << "Test(const Test&)" << endl; }
	Test(Test &&) { cout << "Test(Test &&)" << endl; }
	~Test() { cout << "~Test()" << endl; }
};

int main()
{
	vector<Test> v;
	v.reserve(100);

	Test t1(10);
	cout << "============" << endl;
	//直接插入对象,两个没有区别
	v.push_back(t1);
	v.emplace_back(t1);
	cout << "============" << endl;
	v.push_back(Test(20));
	v.emplace_back(Test(20));
	cout << "============" << endl;
	v.push_back(20);
	//v.push_back(30, 40);
	cout << "============" << endl;
	//给emplace传入Test对象构造所需要的参数,直接在容器底层构造对象
	//省去了临时对象的构造析构
	v.emplace_back(20);
	v.emplace_back(30, 40);
	cout << "============" << endl;
	return 0;
}

来看一下输出结果:
在这里插入图片描述
可以看到在使用emplace_back(20)时省去了临时对象的构造,是根据参数直接在容器底层构造函数,提高了效率。之所以说提高了效率,是因为容器里存储的都是元素的拷贝,副本,使用emplace减少了临时对象的构造及拷贝,自然提高了效率。而且,在使用emplace_back时还可以“像函数调用”一样直接传入参数,无需添加构造,比如v.emplace_back(30, 40);
emplace_back底层是如何实现的呢?
这里仿写一个vector

//容器的空间配置器
template<typename T>
struct CustomAllocator
{
	T* allocate(size_t size)
	{
		return (T*)malloc(size * sizeof(T));
	}

	//deallocate
	void deallocate(T* ptr)
	{
		free(ptr);
	}

	template<typename... Types>
	void construct(T *ptr, Types&&... args)
	{
		new (ptr) T(std::forward<Types>(args)...);
	}

	void destroy(T *ptr)
	{
		
	}
};

template<typename T, typename Alloc = CustomAllocator<T>>
class vector
{
public:
	vector() : vec(nullptr), size(0), idx(0) {}

	void reserve(size_t size) 
	{
		vec = allocator.allocate(size);
		this->size = size;
	}

	//1.
	//void push_back(const T &val)
	//{
	//	//构造一个值为val的对象
	//	allocator.construct(vec + idx, val);
	//	idx++;
	//}

	//void push_back(T &&val)
	//{
	//	allocator.construct(vec + idx, std::move(val));
	//	idx++;
	//}
	
	//2.使用模板
	template<typename Type>
	void push_back(Type&& val)
	{
		allocator.construct(vec + idx, std::forward<Type>(val));
		idx++;
	}

	//可变参模板
	//1.引用折叠 实参:左值Test Types推导为Test& -> Test&+&& = Test&
	//			 实参:右值 Types推导为Test -> Test&&
	template<typename... Types>
	void emplace_back(Types&&... args)
	{
		//无论是左值引用还是右值引用变量,它本身是个左值。
		//2.传递的过程中要保持args的引用类型,使用完美转发
		allocator.construct(vec + idx, std::forward<Types>(args)...);
		idx++;
	}

private:
	T* vec;
	int size;
	int idx;
	Alloc allocator;
};

可以看到对于emplace_back因为参数个数不确定,这里用到了变参模板,以及为了保持引用类型,用到的完美转发技术。使用自定义的vector运行,查看输出可以发现构造部分与本身的vector相同。
在这里插入图片描述

通过这个例子,我们也可以简单的窥视STL库中的vector实现。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

高二的笔记

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值