参考大神链接: https://blog.csdn.net/u012198575/article/details/83142419

1.左值与右值

https://msdn.microsoft.com/en-us/library/f90831hc.aspx

左值(left-values),缩写:lvalues    //也有locator value

右值(right-values),缩写:rvalues

所有的c++表达,不是左值就是右值。

lvalues是指存在于单个表达式之外的对象。你可以把左值当成有名字的对象

所有的变量,包括常变量,都是左值。

rvalues是一个暂时存在的值存在于单个表达式之内的对象。

有点拗口(难理解),通俗来说就是,左值的生存期不只是这句话,后面还能用到它。

右值呢,出了这句话就挂了,所以也叫(将亡值)。

简单定义:

lvalue代表一个在内存中占有确定位置的对象(换句话说就是有一个地址)。
rvalue通过排他性来定义,每个表达式不是lvalue就是rvalue。

因此从上面的lvalue的定义,rvalue是在不在内存中占有确定位置的表达式

 #include <iostream>
using namespace std;
int main()
{
int x = + ;
cout << x << endl;
}

x是左值,3 + 4是右值。

 // lvalues_and_rvalues2.cpp
int main()
{
int i, j, *p; // 正确的使用: 变量是左值
i = ; // 错误的使用: 左边的操作 必须是 左值 (C2106)
= i; // C2106
j * = ; // C2106 // 正确的使用: 被间接引用的指针是左值
*p = i; const int ci = ;
// 错误的使用: 左边的操作 是 常量左值 (C3892)
ci = ; // C3892 // 正确的使用: 条件操作 返回了左值
((i < ) ? i : j) = ;
}

2.左值引用,右值引用

左值引用:https://msdn.microsoft.com/en-us/library/w7049scy.aspx

使用语法:类型 + &(引用符) + 表达式

可以把左值引用当成对象的另一个名字,lvalue引用声明由一个可选的说明符列表和一个引用声明符组成。

引用必须初始化,而且不能改变。

一个对象的地址可以 转化成 一种指定类型的指针 或者 转化成 一个 相似类型的引用。意义是相同的。

demo:

 char c_val = 'c';
char *ptr = &c_val;//&c_val为取c_val地址
char &r_val = c_val;//左值引用表达式 r_val为c_val的引用

不要混淆 取地址 和 引用,当&说明符前面带有类型声明,则是引用,否则就是取地址。

通俗来说   &在"="号左边的是引用

       &在“=”右边的是取地址

右值引用:https://msdn.microsoft.com/en-us/library/dd293668.aspx

使用语法:类型 + && + 表达式     //多了一个&符号

Move Semantics:移动语义

右值引用使您能够区分左值和右值。Lvalue引用和rvalue引用在语法和语义上是相似的。

右值引用支持移动语义的实现,可以显著提升应用程序的性能。移动语义允许您编写将资源(例如动态分配的内存)从一个对象传输到另一个对象的代码,移动语义行之有效,因为它允许从程序中其他地方无法引用的临时对象转移资源。

为了实现移动语义,你在类中提供一个动态构造,和可选择的动态赋值运算符(operator=)。拷贝和赋值操作的资源是右值的可以自动调用移动语义。不像缺省的拷贝构造,编译器并不提供缺省的动态构造。

 #include <iostream>
#include <string>
using namespace std; int main()
{
string s = string("h") + "e" + "ll" + "o";
cout << s << endl;
}

在Visual C++ 2010之前,每个调用 “+”运算符会分配和返回一个新的临时的string对象,

“+”运算符不能从一个string扩展到另一个,因为它不知道string是左值还是右值。

如果源字符串都是lvalues,那么它们可能在程序的其他地方被引用,因此不能被修改。

通过使用右值引用“+”运算符能够修改那些不能在程序中别处引用的右值,所以现在“+”运算符可以有一个string扩展到另一个。

这可以显著减少字符串类必须执行的动态内存分配的数量。

为了更好地理解移动语义,考虑向向量对象插入一个元素的例子。

如果超出了vector对象的容量,vector对象必须为其元素重新分配内存,然后将每个元素复制到另一个内存位置,以便为插入的元素腾出空间。

当插入操作复制一个元素时,它创建一个新元素,调用copy构造函数将数据从前一个元素复制到新元素,然后销毁前一个元素。

移动语义允许您直接移动对象,而不必执行昂贵的内存分配和复制操作。

Perfect Forwarding:完美转发

完美的转发减少了重载函数 避免了转发的问题。转发的问题出现在你写通用函数将引用作为参数,将这些参数由函数调用的时候。

举个例子,如果通用函数将 type const T&作为参数,那么调用函数不能修改参数的值。

如果通用函数 将 type T&作为参数,那么当参数是右值的时候,函数不能调用。

通常来说,为了解决上述的问题,你需要提供重载函数,既要有type const T&参数的函数,也要有type T&参数的函数。

结果呢,重载函数的数量随着参数数量呈指数递增。而右值引用能够使你只用一个函数就能适用于任意数量的参数。

总结:

C++11引入了右值引用和移动语义。

右值引用将左值与右值区分开来。

它们可以帮助您通过消除不必要的内存分配和复制操作来提高应用程序的性能。

它们还使您能够编写接受任意参数的函数的一个版本,并将其转发给另一个函数,就好像直接调用了另一个函数一样

C++的左值,右值,左值引用,右值引用的更多相关文章

  1. ecos3.0编译 if_lancepci.c:528: 错误: 赋值运算的左操作数必须是左值

    /home/xin/ecos3/ecos-3.0/packages/devs/eth/amd/lancepci/v3_0/src/if_lancepci.c:528: 错误: 赋值运算的左操作数必须是 ...

  2. item 24: 区分右值引用和universal引用

    本文翻译自<effective modern C++>,由于水平有限,故无法保证翻译完全正确,欢迎指出错误.谢谢! 博客已经迁移到这里啦 古人曾说事情的真相会让你觉得很自在,但是在适当的情 ...

  3. [android]如何使LinearLayout布局从右向左水平排列,而不是从左向右排列

    方法1: <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:l ...

  4. 5-2-2 printf参数从右往左压栈

    5-2-2 C中printf计算参数时是从右到左压栈的 #include <stdio.h> int main (int argc, char **argv) { ; ,,,,}; int ...

  5. Ueditor增加文字竖排显示和从右向左输入(支持蒙古文和维吾尔文)

    平时我们在ueditor中都是输入的中文,排版都是从左向右输入.但是当输入一些少数民民族言时,ueditor却不能正常显示. 例如蒙古文字,传统蒙文是竖排书写.如下图:传统蒙古文排文方式,<蒙古 ...

  6. const引用返回值

    一.引用 引用是别名 必须在定义引用时进行初始化.初始化是指明引用指向哪个对象的唯一方法. const 引用是指向 const 对象的引用: ; const int &refVal = iva ...

  7. C语言函数入参压栈顺序为什么是从右向左?

    看到有人提问到,在处理printf/cout时,压栈顺序是什么样的?大家都知道是从右往左,也就是说从右往左的计算,但是,这里的计算不等于输出. a++和++a的压栈的区别:在计算时,遇到a++会记录此 ...

  8. C/C++---printf/cout 从右至左压栈顺序实例详解

    __cdecl压栈顺序实例 明白计算:计算是从右到左计算的 栈和寄存器变量:x++,是将计算结果存放到栈空间,最后是要出栈的:而++x和x是将计算结果直接存放到某个寄存器变量中(是同一个),所以计算完 ...

  9. i++为什么不能作为左值,而++i可以作为左值

    今天看书见到如下代码: int a=2; ++a++; 根据操作符的优先级和结合性知,操作符++的优先级为3,结合性为右结合,即++a++;可以理解为++(a++); 但我把代码放在vs2015上,结 ...

  10. Python读字节某一位的值,设置某一位的值,二进制位操作

    Python读字节某一位的值,设置某一位的值,二进制位操作   在物联网实际应用项目开发中,为了提升性能,与设备端配合,往往最终使用的是二进制字节串方式进行的通信协议封装,更会把0和1.True和Fa ...

随机推荐

  1. python 正则表达式实例

    字符匹配 实例 描述 python 匹配 "python". 字符类 实例 描述 [Pp]ython 匹配 "Python" 或 "python&qu ...

  2. python 创建实例对象

    实例化类其他编程语言中一般用关键字 new,但是在 Python 中并没有这个关键字,类的实例化类似函数调用方式. 以下使用类的名称 Employee 来实例化,并通过 __init__ 方法接收参数 ...

  3. HDU 6191 Query on A Tree ( 2017广西邀请赛 && 可持久化Trie )

    题目链接 题意 : 给你一棵树.树上的每个点都有点权.之后有若干次问询.每次问询给出一个节点编号以及一个整数 X .问你以给出节点为根的子树中哪个节点和 X 异或最大.输出这个值 分析 : 看到这种树 ...

  4. 按下enter触发事件

    原理:按下enter的事件属于键盘事件,我们可以先用下面函数来获取enter的键码(键盘上的按键都有各自的键码),通过这个键码可以来判断按下的是哪个键 document.addEventListene ...

  5. Unity3D_(游戏)控制物体的上、下、左、右移动

    通过键盘上↑.↓.←.→实现对物体的控制 using System.Collections; using System.Collections.Generic; using UnityEngine; ...

  6. python学习之路(7)

    调用函数 Python内置了很多有用的函数,我们可以直接调用. 要调用一个函数,需要知道函数的名称和参数,比如求绝对值的函数abs,只有一个参数.可以直接从Python的官方网站查看文档: http: ...

  7. Android Studio基本使用

    1.    创建Android项目 1)    Application name:应用名称,launcher界面显示的 2)    Company Domain:公司域名(sprd.com) 3)   ...

  8. bootstrap editable有默认值

    function listEditor(data,productCode) { $('#tab1').bootstrapTable('load', data); $('#tab1').bootstra ...

  9. var $this = $(this)

    jQuery: What’s the Difference Between $(this), $this, and this? What about $this? $this is a little ...

  10. Note: Time clocks and the ordering of events in a distributed system

    http://research.microsoft.com/en-us/um/people/lamport/pubs/time-clocks.pdf 分布式系统的时钟同步是一个非常困难的问题,this ...