目录
1、统一的列表初始化
2、所有容器新增initializer_list构造
3、auto、decltype和typeid
4、nullptr
5、 范围for
6、STL中的变化
array(新容器)
forward_list(新容器)
cbegin、cend、crbegin、crend(新方法)
7、右值引用和移动语义(重点)
1)什么是左值?什么是左值引用?
2)什么是右值?什么是右值引用?
3)什么是移动拷贝/赋值
4)move
8、完美转发
右值引用和左值引用本身是左值还是右值?
万能引用
1、统一的列表初始化
一切皆可以用{}初始化,且 = 可以不写
2、所有容器新增initializer_list构造
注意:这两句代码用的不是同一个语法。
第一句代码是用initializer_list实现的,它是用一个常量数组构造一个initializer_list(原理是它有两个指针,指向数组空间的开始和结束位置),C++11里vector里实现了以initializer_list为参数的构造函数。
第二句才是前面提到的列表初始化。
所有容器都实现了以initializer_list为参数的构造函数,都可以用上面的写法。
3、auto、decltype和typeid
1)auto可以进行类型推导,函数指针也可以用auto来定义推导。
2)但如果我只是想声明一个变量,那么可以用decltype。
decltype(pf1)pf2;这句代码就是推导出pf1的类型然后用这个类型定义一个pf2。
decltype可以用来定义变量,也可以用来做模板实参,就是当一个类型用。
3)typeid也可以推导类型,但它只能打印来看,不能用。
4、nullptr
nullptr也是C++11的,因为NULL在C语言里被定义成字面量0,会有一些歧义,所以有了nullptr。
5、 范围for
范围for循环通过遍历给定容器的begin()和end()函数返回的迭代器范围,来遍历容器中的每一个元素。用的比较多,不多讲了。
6、STL中的变化
array(新容器)
相当于静态数组增加了一个越界检查功能。
forward_list(新容器)
单链表,不支持尾插尾删,insert,erase也只支持了after。比较鸡肋。
cbegin、cend、crbegin、crend(新方法)
返回const迭代器。
7、右值引用和移动语义(重点)
1)什么是左值?什么是左值引用?
左值是一个数据的表达式(如变量名或解引用的指针),我们可以获取它的地址,一般可以对它赋值,只有左值可以出现在赋值符号的左边,右值不行。左值引用就是对左值的引用,给左值取别名,左值引用的符号是&。
左值引用的使用价值:减少拷贝
1、做参数 2、做返回值
但左值引用一直没有解决的问题是局部变量无法通过左值引用返回。
2)什么是右值?什么是右值引用?
右值不能取地址,一般是在赋值符号右边,但不能出现在赋值符号左边。对右值取别名就是右值引用,右值引用的符号是&&。
内置类型的右值叫纯右值,自定义类型的右值叫将亡值
下面两个函数构成重载吗?
答案是构成,虽然两个函数都能用,但编译器会调用更匹配的那个,也是就第二个func,如果没有第二个func,第一个也行。
3)什么是移动拷贝/赋值
对于右值将亡值,可以通过交换两个对象的资源来减少拷贝。对于下面的例子,加上编译器做出优化,虽然str是左值,但由于它出了作用域就销毁了,编译器会识别str是右值将亡值,然后调用右值引用的拷贝构造,即移动拷贝。
string& operator=(string && s) 和 string& operator=(const string & s)构成重载,如果是右值的拷贝构造,就调用第一个,否则调用第二个
需要深拷贝的类,才需要实现移动赋值。
4)move
move可以理解为将一个左值转成右值将亡值,然后将所有权转给另一个对象。
int main() { // 创建一个vector对象v1,包含一些整数 std::vector<int> v1 = {1, 2, 3, 4, 5}; // 使用std::move将v1的所有权转移给v2 std::vector<int> v2 = std::move(v1); return 0; }
8、完美转发
右值引用和左值引用本身是左值还是右值?
int a= 10; int &r = a; int &&rr = 10;
r和rr都是左值,否则如果右值引用的属性不是左值的话,下面的场景就无法实现:
s本身是左值,才有可能传给swap(string& s)
万能引用
template<typename T> void PerfectForward(T && t){ Fun(t); }
T&&:这是万能引用,既可以接收左值,也可以接收右值。
如果实参是左值,他就是左值引用(引用折叠)
如果实参是右值,他就是右值引用
注意:因为左值和右值引用本身一定是左值,所以t本身一定是左值。所以最后无论传的实参是左值还是右值,调用的都是左值引用。
如何让t保持T它原本的属性? 完美转发
template<typename T> void PerfectForward(T && t){ Fun(forward<T>(t)); }