C++11 emplace_back和push_back区别
Hello!!大家早上中午晚上好!!今天我们来看看emplace_back到底是什么?
一、看原型
1.1emplace_back原形(list容器下)
1.2push_back原形(list容器下)
前面已经复习过万能引用、引用折叠了所以对于emplace_back中Args&&表示的意思不多解释,我们来着重看模版参数中的 Args前的...和函数中跟在Args&&后面的...三个点,什么意思?
二、可变参数模版
2.1C++11新增的可变参数模版概念
在定义模版的时候可以这么定义:
template <class... Argus>
Argus是模版参数包,...Argus表示拥有0到N个任意来类型参数的参数包;
也可以这么定义:
template<calss T,class... Argus>
Argus是模版参数包,...Argus表示拥有1到N个任意类型参数的参数包;因为在Argus之前定义了一个T
以此类推:
template<class T1,class T2,class... Arugs>
Argus是个模版参数包,拥有过2到N个任意类型参数的参数包
...
2.2如何拿到参数包里的参数?
方法一:递归方式展开
void Print()
{
cout << endl;
}
template <class T,class ...Args>
void Print(T first,Args... args)
{
cout << first <<" ";
Print(args...);
}
int main()
{
Print(10);
Print(10, 11.1);
Print(10, 11.1, "hello");
return 0;
}
运行:
递归方式的缺点就是必须要重载一个终止递归的函数(当参数为0);
方法二:逗号表达式+列表初始化
template<class ...Argu>
void Print(Argu... argu)
{
initializer_list<int> il = { (cout << argu << " ",0)...};
cout << endl;
}
int main()
{
Print(1);
Print(1,2.2);
Print(1,2.2,"hello");
return 0;
}
运行:
注:
逗号表达式运行结果为最后一个值,会把逗号分隔的内容按顺序运行一遍;
列表初始化保证初始化的值必须从左往右;
三、emplace_back 和push_back区别
3.1、emplace_back是函数模版,且是可变参数模版,通过传入不同参数类型,实例化出不同类型的emplace_back函数;push_back是类成员函数;
3.2、empalec_back底层:
emplace_back 函数的参数类型是可变数量的 万能引用
,参数通过 完美转发
到容器 内部进行对象创建构造,可以有效减少参数传递过程中产生临时对象,避免了对象的移动和拷贝操作。
push_back在参数传递的过程中会产生临时对象,增加拷贝构造或移动构造的操作;
测试:
#include <vector>
class testDimo
{
public:
testDimo(int id)
:_id(id)
{
cout << "普通构造" << endl;
}
testDimo(const testDimo&t)
: _id ( t._id)
{
cout << "拷贝构造" << endl;
}
testDimo(testDimo&& t)
:_id(t._id)
{
cout << "移动构造" << endl;
}
private:
int _id;
};
int main()
{
vector<testDimo>v1;
v1.push_back(1);
cout << endl;
vector<testDimo>v2;
v2.emplace_back(1);
return 0;
运行:
3.3总结
emplace_back相比于push_back只是减少了拷贝构造或移动构造的操作而已;
只要我们实现了移动构造,push_back的代价跟emplace_back不会相差太多!