绍兴住房和城乡建设厅网站首页,基于wordpress的英文小游戏站,垂直网站建设,界面设计的重要性【导读】#xff1a;本文主要详细介绍了左值、右值、左值引用、右值引用以及move、完美转发。左值和右值左值(left-values)#xff0c;缩写#xff1a;lvalues右值(right-values)#xff0c;缩写#xff1a;rvalues直接上官网查#xff0c;我一向倡导自己去懂得原理… 【导读】本文主要详细介绍了左值、右值、左值引用、右值引用以及move、完美转发。左值和右值左值(left-values)缩写lvalues右值(right-values)缩写rvalues直接上官网查我一向倡导自己去懂得原理而原理都是老外写的当然我只是针对c 编程语言这样说。https://msdn.microsoft.com/en-us/library/f90831hc.aspx翻译所有的c 表达不是左值就是右值。lvalues是指存在于单个表达式之外的对象。你可以把左值当成有名字的对象。所有的变量包括常变量都是左值。rvalues是一个暂时存在的值存在于单个表达式之内的对象。有点拗口(难理解)通俗来说就是左值的生存期不只是这句话后面还能用到它。而右值呢出了这句话就挂了所以也叫(将亡值)。它举了一个栗子#include using namespace std; int main() { int x 3 4; cout endl; } 在以上实例中很显然x是左值3 4是右值。它又举了一个栗子来说明错误的使用和正确的使用// lvalues_and_rvalues2.cpp int main() { int i, j, *p; // 正确的使用: 变量是左值 i 7; // 错误的使用: 左边的操作 必须是 左值 (C2106) 7 i; // C2106 j * 4 7; // C2106 // 正确的使用: 被间接引用的指针是左值 *p i; const int ci 7; // 错误的使用: 左边的操作 是 常量左值 (C3892) ci 9; // C3892 // 正确的使用: 条件操作 返回了左值 ((i 3) ? i : j) 7; } 左值引用、右值引用左值引用参考说明书《Lvalue Reference Declarator: 》网站如下https://msdn.microsoft.com/en-us/library/w7049scy.aspx使用语法类型 (引用符) 表达式type-id cast-expression 翻译你可以把左值引用当成对象的另一个名字lvalue引用声明由一个可选的说明符列表和一个引用声明符组成。引用必须初始化而且不能改变。一个对象的地址可以 转化成 一种指定类型的指针 或者 转化成 一个 相似类型的引用。意义是相同的。demo:char c_val c;char *ptr c_val;char r_val c_val;不要混淆 取地址 和 引用当说明符前面带有类型声明则是引用否则就是取地址。通俗来说 在 ”” 号左边的是引用右边的是取地址。右值引用参考说明书《Rvalue Reference Declarator: 》网站如下https://msdn.microsoft.com/en-us/library/dd293668.aspx使用语法类型 表达式type-id cast-expression 翻译Move Semantics移动语义右值引用使您能够区分左值和右值。Lvalue引用和rvalue引用在语法和语义上是相似的。右值引用支持移动语义的实现可以显著提升应用程序的性能。移动语义允许您编写将资源(例如动态分配的内存)从一个对象传输到另一个对象的代码移动语义行之有效因为它允许从程序中其他地方无法引用的临时对象转移资源。为了实现移动语义你在类中提供一个动态构造和可选择的动态赋值运算符(operator)。拷贝和赋值操作的资源是右值的可以自动调用移动语义。不像缺省的拷贝构造编译器并不提供缺省的动态构造。demo:#include #include using namespace std; int main() { string s string(h) e ll o; cout endl; } 在Visual C 2010之前每个调用 “ ”运算符会分配和返回一个新的临时的string对象“ ”运算符不能从一个string扩展到另一个因为它不知道string是左值还是右值。如果源字符串都是lvalues那么它们可能在程序的其他地方被引用因此不能被修改。通过使用右值引用“ ”运算符能够修改那些不能在程序中别处引用的右值所以现在“ ”运算符可以有一个string扩展到另一个。这可以显著减少字符串类必须执行的动态内存分配的数量。为了更好地理解移动语义考虑向向量对象插入一个元素的例子。如果超出了vector对象的容量vector对象必须为其元素重新分配内存然后将每个元素复制到另一个内存位置以便为插入的元素腾出空间。当插入操作复制一个元素时它创建一个新元素调用copy构造函数将数据从前一个元素复制到新元素然后销毁前一个元素。移动语义允许您直接移动对象而不必执行昂贵的内存分配和复制操作。Perfect Forwarding完美转发完美的转发减少了重载函数 避免了转发的问题。转发的问题出现在你写通用函数将引用作为参数将这些参数由函数调用的时候。举个例子如果通用函数将 type const T作为参数那么调用函数不能修改参数的值。如果通用函数 将 type T作为参数那么当参数是右值的时候函数不能调用。通常来说为了解决上述的问题你需要提供重载函数既要有type const T参数的函数也要有type T参数的函数。结果呢重载函数的数量随着参数数量呈指数递增。而右值引用能够使你只用一个函数就能适用于任意数量的参数。原先的做法如下先写出所有适用的通用函数struct W { W(int, int) {} }; struct X { X(const int, int) {} }; struct Y { Y(int, const int) {} }; struct Z { Z(const int, const int) {} }; 再将带有不同类型的参数的函数用模板结合起来template typename T, typename A1, typename A2 T* factory(A1 a1, A2 a2) { return new T(a1, a2); } 调用需要根据适用的类型用相应的指针对接。当调用的是左值时int a 4, b 5; W* pw factory(a, b); 当调用的是右值时。但是下面的示例中没有包含对工厂函数的有效调用因为工厂将可修改的lvalue引用作为其参数但是它是通过使用右值调用的:这里要注意的是const int 是lvalue 而不是 rvalue而2是rvalue函数会编译不过。Z* pz factory(2, 2); 为了解决这类问题需要将模板函数修改成如下形式右值引用可以适用const T 和 T形式的参数template typename T, typename A1, typename A2 T* factory(A1 a1, A2 a2) { return new T(std::forward(a1), std::forward(a2)); } 经过上述修改均可以调用如下图代码所示