C++进阶 C++11(上) 一.列表初始化{}1.列表初始化C98中的{}只能初始化数组结构体C11中的{}统一所有初始化方式全部使用同一种语法为什么能初始化类对象本质先构造临时对象然后:再经过编译器优化直接变成可以省略以前现在2. initializer_list如果想:数量不固定。不能写C11提供:会生成一个临时数组然后:内部保存两个指针所以:可以遍历vector如何支持map如何支持二.右值引用和移动语义1.左值和右值1.左值能取地址例如所以a是左值都是左值2.右值不能取地址。2.左右值引用1.左值引用给左值取别名2.右值引用给右值取别名。3.延长生命周期因为右值是临时变量马上要销毁。例如里面可能有马上析构。如果能把资源偷走直接拿过来效率会高很多move其实他不是移动数据move只干一件事强制转成右值例如等价于生命周期延长正常下一行就销毁。但被引用绑定以后 r 的生命周期延长4.移动构造传统拷贝构造复制资源。代价很大。移动构造:假设s中直接交换:不需要复制字符例如:原来100万字符的拷贝复杂度为O(N)直接交换指针复杂度为O(1)5.移动赋值传统:复制所以字符移动赋值直接接管资源效率极高6.右值引⽤和移动语义解决传值返回问题以前:两次深拷贝。C11直接消灭拷贝所以:这种超大对象也敢传值返回。三.引用折叠1.引用折叠的定义展开后此时就产生了引用的引用而C不允许真正存在引用的引用。所以编译器必须把它折叠成一个合法类型。这就是引用折叠2.引用折叠规则记住一句话只有 右值引用 右值引用 右值引用其余全部折叠成左值引用3. 举例理解情况1展开:折叠:情况2展开:结果:情况3展开结果:情况4展开结果:4. 模板中的引用折叠例如:很多人认为:一定是右值引用。实际上不是。因为T是模版参数它会发生类型推导。情况1传右值10是 int类型右值所以:情况2传左值X是左值所以:折叠后:四.完美转发1.为什么需要完美转发假设有两个重载函数:很多人以为输出结果是:实际上:这是为什么呢看第二次调用模板推导此时t的类型确实是但是表达式t是变量而变量表达式永远是左值例如:虽然rr的类型是:但rr这个表达式是左值所以:调用的是:但我们希望:传下去还是左值传下去还是右值。但是:无论如何t都是左值最终都会调用:这就丢失了原来的值类别2.解决方案std::forwardC11 提供:用于保留原来的属性输出:3.forward原理实际上核心就一句传右值时:模版推导所以展开:得到右值于是:被调用传左值时模版推导:展开:折叠后:变成左值调用