C++11:可变参数模板 && emplace_back

可变参数模板

基本概念:C++ 的参数模板是 C++11 引入的特性,它允许模板接受可变数量的参数

// Args是一个模板参数包,args是一个函数形参参数包
// 声明一个参数包Args... args,这个参数包中可以包含0到N个模板参数。
template <class ...Args>
void ShowList(Args... args)
{}

emplace_back 

基本概念:emplace_back是C++11提供的一个基于可变参数模板实现的新的成员函数

我们用下面这段代码来尝试一下emplace_back和push_back的区别:

///验证深拷贝
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;

#include<vector>
#include<list>
#include<map>
#include<set>
#include<string>

#include<assert.h>

namespace bit
{
	class string
	{
	public:
		typedef char* iterator;
		iterator begin()
		{
			return _str;
		}

		iterator end()
		{
			return _str + _size;
		}

		string(const char* str = "")
			:_size(strlen(str))
			, _capacity(_size)
		{
			cout << "string(char* str)" << endl;

			_str = new char[_capacity + 1];
			strcpy(_str, str);
		}

		// s1.swap(s2)
		void swap(string& s)
		{
			::swap(_str, s._str);
			::swap(_size, s._size);
			::swap(_capacity, s._capacity);
		}

		// 拷贝构造 -- 左值
		string(const string& s)
			:_str(nullptr)
		{
			cout << "string(const string& s) -- 深拷贝" << endl;

			_str = new char[s._capacity + 1];
			strcpy(_str, s._str);
			_size = s._size;
			_capacity = s._capacity;
		}

		// 移动构造 -- 右值(将亡值)
		string(string&& s)
		{
			cout << "string(string&& s) -- 移动拷贝" << endl;
			swap(s);
		}

		// 拷贝赋值
		// s2 = tmp
		string& operator=(const string& s)
		{
			cout << "string& operator=(const string& s) -- 深拷贝" << endl;
			string tmp(s);
			swap(tmp);

			return *this;
		}

		// 移动赋值
		string& operator=(string&& s)
		{
			cout << "string& operator=(string&& s) -- 移动拷贝" << endl;
			swap(s);

			return *this;
		}

		~string()
		{
			delete[] _str;
			_str = nullptr;
		}

		char& operator[](size_t pos)
		{
			assert(pos < _size);
			return _str[pos];
		}

		void reserve(size_t n)
		{
			if (n > _capacity)
			{
				char* tmp = new char[n + 1];
				strcpy(tmp, _str);
				delete[] _str;
				_str = tmp;

				_capacity = n;
			}
		}

		void push_back(char ch)
		{
			if (_size >= _capacity)
			{
				size_t newcapacity = _capacity == 0 ? 4 : _capacity * 2;
				reserve(newcapacity);
			}

			_str[_size] = ch;
			++_size;
			_str[_size] = '\0';
		}

		//string operator+=(char ch)
		string& operator+=(char ch)
		{
			push_back(ch);
			return *this;
		}

		const char* c_str() const
		{
			return _str;
		}
	private:
		char* _str = nullptr;
		size_t _size = 0;
		size_t _capacity = 0; // 不包含最后做标识的\0
	};

	bit::string to_string(int value)
	{
		bool flag = true;
		if (value < 0)
		{
			flag = false;
			value = 0 - value;
		}

		bit::string str;
		while (value > 0)
		{
			int x = value % 10;
			value /= 10;
			str += ('0' + x);
		}
		if (flag == false)
		{
			str += '-';
		}

		std::reverse(str.begin(), str.end());
		return str;
	}
}
int main()
{
	std::list<bit::string> lt1;

	bit::string s1("xxxx");
	lt1.push_back(s1);
	lt1.push_back(move(s1));
	cout << "=============================================" << endl;

	bit::string s2("xxxx");
	lt1.emplace_back(s2);
	lt1.emplace_back(move(s2));
	cout << "=============================================" << endl;

	lt1.push_back("xxxx");
	lt1.emplace_back("xxxx");
	cout << "=============================================" << endl;

	std::list<pair<bit::string, bit::string>> lt2;
	pair<bit::string, bit::string> kv1("xxxx", "yyyy");
	lt2.push_back(kv1);
	lt2.push_back(move(kv1));
	cout << "=============================================" << endl;

	pair<bit::string, bit::string> kv2("xxxx", "yyyy");
	lt2.emplace_back(kv2);
	lt2.emplace_back(move(kv2));
	cout << "=============================================" << endl;

	lt2.emplace_back("xxxx", "yyyy");
	cout << "=============================================" << endl;


	return 0;
}

验证浅拷贝
class Date
{
public:
	Date(int year, int month, int day)
		:_year(year)
		, _month(month)
		, _day(day)
	{
		cout << "Date(int year, int month, int day)" << endl;
	}

	Date(const Date& d)
		:_year(d._year)
		, _month(d._month)
		, _day(d._day)
	{
		cout << "Date(const Date& d)" << endl;
	}
private:
	int _year = 1;
	int _month = 1;
	int _day = 1;
};

int main()
{
	std::list<Date> lt1;
	lt1.push_back({ 2024,3,30 });

	// 不支持
	//lt1.emplace_back({ 2024,3,30 });

	// 推荐
	lt1.emplace_back(2024, 3, 30);

	cout << endl;
	Date d1(2023, 1, 1);
	lt1.push_back(d1);
	lt1.emplace_back(d1);

	cout << endl;
	lt1.push_back(Date(2023, 1, 1));
	lt1.emplace_back(Date(2023, 1, 1));


	return 0;
}

结论:

1、对于插入单个对象而言,emplace_back和push_back没有区别

2、对于需要深拷贝的类对象,emplace_back可以减少一次移动构造

3、对于需要浅拷贝的类对象,emplace_back可以减少一次拷贝构造

4、emplace_back不支持使用{}传参

5、emplace_back可以用于尾插不支持拷贝构造的自定义类(由3推出)

~over~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值