——原创,引用请附带博客地址

2019-12-06 23:42:18 这篇文章分析的还是不行,先暂时放在这以后再更新。

本篇比较长,需要耐心阅读

以一个实际问题开始分析

class Sub{}
Sub GetInstance(){
return Sub();
}
int main(){
Sub a=GetInstance();
....
////////////////////////////////////////////////////////////////////

【分析】:例子比较简易,主要通过GetInstance方法返回一个Sub实例,在这个过程中,发生的事情如下:

  1. GetInstance内部执行Sub()构造一次,由于是临时变量,在函数结束后被析构。
  2. 返回的临时变量又克隆一份给返回值,这个过程调用一次复制构造函数
  3. 在main函数中,由于赋值又调用了一次复制构造函数

整个过程执行了三次构造(包括复制构造),最关键的问题在于,在GetInstance()方法中第一次构造的Sub实例在函数结束后被析构,存在的意义只在于被复制构造给返回值。

又假定,如果Sub对象非常巨大,那么得到实例a的代价非常巨大。整个来看,函数内构造的Sub实例没有太大意义,一个设想是能不能把这个Sub实例保存下来,这样至少节省了一次构造。换句话说,能不能把将要消失的临时对象保存下来,延长它的生命周期?

左值右值定义

一般说法,可以取地址的,有名字的是左值,反之,不能取地址,没有名字的是右值。
比如:a=b+c;
&a是允许的操作,而&(b+c)不能通过编译,因此a是一个左值,而(b+c)是一个右值。

C++11中,右值由两个概念组成,一个是将亡值,另一个是纯右值

纯右值

纯右值是C++98中标准中右值的概念,主要用于辨识临时变量和一些不跟对象关联的值。
(*注:不跟对象关联,这段话非常特别,后面再解释)

比如:非引用返回的函数返回的临时变量值就是纯右值。
1. 一些运算表达式,比如1+3产生的临时变量值为纯右值。
2. 不跟对象关联的字面量值,比如2、'c'、true等,也是纯右值。

将亡值

将亡值是C++11新增的跟右值引用相关的表达式,这种表达式通常是将被移动的对象(移为他用),比如返回右值引用T &&的函数返回值、std::move的返回值(后面详细解释)

在C++11的程序中,所有的值必属于左值、将亡值、纯右值三者之一

右值引用

一个小例子说明

int && Add(){
return +;
}

【分析】:方法Add返回一个右值,一般情况下,此处的右值随着方法结束而消失,但是通过右值引用,可以将生命周期延续,此处的 int &&就是右值引用。

左右值引用的绑定

一般来说,右值引用不能绑定左值,比如:
int a=10;
int &&b=a;
此处不能通过。

那么,左值引用能不能绑定右值呢?

int && Add(){ //右值引用
  return 1+2;
}
int &a=Add();

此处不能通过编译,但是有一个例外,像下面这种情形是可以的。
const int &a=Add();

唯独多了一个const,这个const很神奇,下面详细解释一下const

const

被const修饰的常量左值引用,可以接纳非常量左值常量左值右值对其进行初始化,是什么意思呢?下面以例子说明

void Add(const int &a,const int &b){
std::cout<<a+b<<std::endl;
}

【分析】:Add方法的形参是两个const左值引用,因此在调用时分为三种情形:
1.
const int a=1;
const int b=2;
Add(a,b); //这种属于常量左值入参

2.
int a=1;
int b=2;
Add(a,b); //这种属于非常量左值入参

3.
Add(1,2); //这种属于右值,直接拿右值1,2进行调用

尤其对于第3种情形,如果Add的形参不是常量左值引用,比如 Add(int a,int b),那么第3种情形不能通过。

可以看出,const常量左值引用接纳能力非常强,算是“万能”引用类型。因此,const左值引用可以绑定右值
比如:const int & a=10;完全可行,

但是,常量左值引用有一个缺点,就是其生存周期中只能是“只读的”。

函数返回值究竟是什么是类型?

首先将前面的分析做个阶段总结
1. 右值引用不能绑定左值
2. 左值引用绑定右值分为两种情况:
(1) 如果是非const的左值引用只能绑定左值
(2) const常量左值引用几乎是万能的,可以绑定常量、非常量左值,或右值
下面看个例子:
class Sub{...}

Sub GetInstance(){
return Sub();
}
Sub &sub=GetInstance(); //可以通过编译

【分析】:GetInstance()返回的究竟是哪种类型呢?
如果是右值,根据前面的结论,非常量左值引用是不可以绑定右值的,但结果是编译可以通过。

这个问题很神奇,现在的结论是:函数返回的都是右值

回到最前面的右值定义:

这里提到一句,不跟对象关联的值,但是上述GetInstance方法返回的是类Sub的实例,所以,这里算不算是特殊对待呢?

将VS的警告级别提升,可以看到如下警告:

从警告中可以推断出,函数返回的确实是右值,而编译器在这里使用了“非标准扩展初始化”才会使这一句通过。

结论如下:

函数返回的是右值,但是和对象有关联的右值,似乎规则放松了一点,可以被非常量左值引用绑定,使用的是【非标准扩展初始化】

12232

【原创】C++11:左值和右值(深度分析)的更多相关文章

  1. c++ 11 移动语义、std::move 左值、右值、将亡值、纯右值、右值引用

    为什么要用移动语义 先看看下面的代码 // rvalue_reference.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #includ ...

  2. C++ 11 左值,右值,左值引用,右值引用,std::move, std::foward

    这篇文章要介绍的内容和标题一致,关于C++ 11中的这几个特性网上介绍的文章很多,看了一些之后想把几个比较关键的点总结记录一下,文章比较长.给出了很多代码示例,都是编译运行测试过的,希望能用这些帮助理 ...

  3. C++11 左值、右值、右值引用详解

    C++11 左值.右值.右值引用详解 左值.右值 在C++11中所有的值必属于左值.右值两者之一,右值又可以细分为纯右值.将亡值. 在C++11中可以取地址的.有名字的就是左值,反之,不能取地址的.没 ...

  4. C++11 左值、右值、右值引用

    左值.右值 在C++11中所有的值必属于左值.右值两者之一,右值又可以细分为纯右值.将亡值.在C++11中可以取地址的.有名字的就是左值,反之,不能取地址的.没有名字的就是右值(将亡值或纯右值).举个 ...

  5. [转]C++11 左值、右值、右值引用详解

    https://blog.csdn.net/hyman_yx/article/details/52044632 左值.右值 在C++11中所有的值必属于左值.右值两者之一,右值又可以细分为纯右值.将亡 ...

  6. c++11の的左值、右值以及move,foward

    左值和右值的定义 在C++中,可以放到赋值操作符=左边的是左值,可以放到赋值操作符右边的是右值.有些变量既可以当左值又可以当右值.进一步来讲,左值为Lvalue,其实L代表Location,表示在内存 ...

  7. 左值与右值,左值引用与右值引用(C++11)

    右值引用是解决语义支持提出的 这篇文章要介绍的内容和标题一致,关于C++ 11中的这几个特性网上介绍的文章很多,看了一些之后想把几个比较关键的点总结记录一下,文章比较长.给出了很多代码示例,都是编译运 ...

  8. C++11之右值引用(一):从左值右值到右值引用

    C++98中规定了左值和右值的概念,但是一般程序员不需要理解的过于深入,因为对于C++98,左值和右值的划分一般用处不大,但是到了C++11,它的重要性开始显现出来. C++98标准明确规定: 左值是 ...

  9. C++11 左值与右值

    概念 左值:表达式结束后依然存在的对象 右值:表达式结束后就不存在的临时对象 2.如何判断左值和右值 能不能对表达式取地址,如果能,就是左值,否则就是右值 3.对下面的语句进行区分 int a = 3 ...

随机推荐

  1. 压缩及解压命令gzip、bzip2、tar

    1. gzip 描述:压缩与解压缩 用法:gzip[选项]...[文件名称]... 选项:-d 解压 gzip hello.txt     # 文件压缩后名为hello.txt.gz gzip -d ...

  2. Django之路——11 Django用户认证组件 auth

    用户认证 auth模块 1 from django.contrib import auth django.contrib.auth中提供了许多方法,这里主要介绍其中的三个: 1.1 .authenti ...

  3. Python 字符串正则处理实例

    #coding:utf-8 ''' Created on 2017��9��6�� @author: li.liu ''' from selenium import webdriver from se ...

  4. Beta冲刺(1/7)——2019.5.22

    所属课程 软件工程1916|W(福州大学) 作业要求 Beta冲刺(1/7)--2019.5.22 团队名称 待就业六人组 1.团队信息 团队名称:待就业六人组 团队描述:同舟共济扬帆起,乘风破浪万里 ...

  5. 2019-2020-1 20199301《Linux内核原理与分析》第九周作业

    第八章 进程的切换和系统的一般执行过程 进程的调度实际与进程的切换 ntel定义的中断类型 硬中断:就是CPU的两根引脚(可屏蔽中断和不可屏蔽中断) 软中断/异常:包括除零错误.系统调用.调试断点等在 ...

  6. uva12558埃及分数

    1,看这全英文的题目就怪蛋疼的. 2,这输入也是奇奇怪怪的的.3,想要好好做题,理解做题,就得好好看题自己要理解吸收消化.单纯看别人的话,说实话并没有什么用处. 一,看题. 1,首先,枚举的分数肯定不 ...

  7. Guava com.google.common.base.Stopwatch Spark程序在yarn中 MethodNotFound

    今天在公司提交一个Spark 读取hive中的数据,写入JanusGraph 的app,自己本地调试没有问题,放入环境中提交到yarn 中时,发现app 跑不起. yarn 中日志,也比较明显,app ...

  8. less简介及其编译原理

    一.less环境安装 ①首先需要在电脑上安装nodejs,一般会内置npm,利用以下命令可以检测: ②利用npm在线安装less,运行  npm install –g less ③查看是否安装成功,L ...

  9. python 判断一个字符串组合后,是否在另一个字符串中

    code #coding=utf- def getdic(s): dic = {} for i in s: if (i not in dic): dic[i] = else: dic[i] += re ...

  10. 3ds Max学习日记(十一)——如何给模型上贴图

    参考链接:https://jingyan.baidu.com/article/e4511cf38a810b2b845eaf1f.html   之前一直都不知道怎么在3dsMax里给模型上材质和贴图,被 ...