c++| c++11的新特性
- 左,右值引用
- 什么是左值,右值
- 左值引用和右值引用
- 右值引用解决什么问题呢?
- 移动构造
- 万能引用
- 形式
- 完美转发
- 格式
- lambada表达式
- 格式
- 可变参数模板
- 可变参数模板实现打印不同类型
- emplace_push
- 以list的emplace_back的实现举例
左,右值引用
什么是左值,右值
左右值的语法上的区别就是能不能取地址。
int a = 10; a 可以取地址 是左值, 但是 10不能取地址 是右值。
常见的右值还有匿名对象,表达式返回值,字面常量(就是直接写出来的值比说刚刚的10)等。
左值引用和右值引用
左值引用 T &val , 右值应用 T&& val
一般的左值引用,只能引用只能引用左值,右值引用只能引用右值。
但是const & 可以引用右值
右值引用解决什么问题呢?
对于一个函数返回值不能用引用且拷贝开销很大的情况
。比如to_string 的返回值 就是string 不能是 &string 因为 它的生命周期只在函数内部。str 出了to_string 就销毁了。
my::string s1 = my::to_string(123);
// 会经历 str 的构造,拷贝构造临时对象(深拷贝),赋值构造(深拷贝) s1 开销就很大
所以我们用移动构造优化它
移动构造
就是 参数是右值引用的构造。
string(string&& s)
:_str(nullptr)
{
cout << "string(string&& s) -- 移动构造" << endl;
swap(s);
}
// 移动赋值
string& operator=(string&& s)
{
cout << "string(string&& s) -- 移动赋值" << endl;
swap(s);
return *this;
}
大大节省了深拷贝的成本。
2.匿名对象直接当作函数的参数
string s1 = "hh";
vector<string> v;
v.push_back(s1);
//
v.push_back("hh");
上面的写法先构造s1,然后s1再拷贝构造给v中的data。
下面的写法是构造匿名对象,然后匿名对象直接移动构造给data,就不走深拷贝了。
值得注意的是右值引用本身的属性是左值的因为这样才能修改。左值有常属性。
万能引用
形式
template class<T &&>
void func(T && val)
{
....
}
与右值引用的区别就是上面带了个模板,我们传右值他就识别成右值,传左值它识别成左值
完美转发
格式
template class<T &&>
void func(T && val) //万能引用
{
do_something(forword<T>(val)); // 完美转发
}
完美转发常常和完美应用一起使用的,主要是防止右值引用的属性是左值,传给下一层被认为是左值了,从而走不到移动构造,移动拷贝等。
lambada表达式
lambada表达式本质编译器帮我们生产了一个仿函数。
格式
[]()-> return {} // -> 和return 可省 但是这[] 捕获列表不能省
//比如
[](int x, int y ) -> return (x+y;);
[=] 传值的方式捕获同一作用域的所有变量
[&]传引用的方式捕获同一作用域的所有变量
还可以混用比如[&,a,b]。 除了a,b 以外按转值捕获,其他按引用捕获。
可变参数模板
template class<...Args>
void func(Args ...args)
{
}
可变参数模板实现打印不同类型
// 编译时确定类型,所以要_cpp_print() 递归到最后,参数为空。
void _cpp_print()
{
}
template<class T,class ... Args>
void _cpp_print(T & val, Args ...args)
{
cout << val << " ";
_cpp_print(args...);
}
template <class ...Args >
void cpp_print(Args... args)
{
_cpp_print(args...);
}
template <class T>
int printArg(T &t)
{
cout << t << " ";
return 0;
}
template <class ...Args>
void cpp_print(Args...args)
{
int arr[] = { printArg(args)... };
}
emplace_push
emplace_back 用的就是可变参数模板,在参数大于1的情况下,emplace_back 的效率比push_bakc更高。因为push_back 对于左值中间会走构造然后拷贝构造,对于右值会走构造,然后移动构造。
但是emplace_back 是直接传递的参数包,最后底层直接构造。