IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> 左值、右值、左值引用和右值引用 -> 正文阅读

[C++知识库]左值、右值、左值引用和右值引用

左值和右值

什么是左值和右值?

按照我们常规理解左值就是在等号左边的值,右值是等号右边的值。如果你要这么理解,你就会发现遇到++ii++这一类的语句你就开始混乱了!

其实左值和右值是我们习惯性的叫法,他的全拼应该是:
左值是:locator value(可寻址的数据)
右值是:read value(不可寻址的数据或用来读的数据)

我们常规去理解,应该理解为:
在该程序语句之后能再找到该值,就是左值;否则就是右值。就是不可寻址!

举例说明

左值:

++x;
y*=33;
//这里面++x是直接对x自增,我们得到的值就是x的值,
//是可以后来直接使用x这个变量去使用这个值的。

右值:

x++;
y+3;
123//y+3这个值会被计算,但是没有被承接到,
//后来即便我们再用y+3去获得这个临时的值,大小是一样的,
//但不是我上次计算的那个值,我又经过了以此计算的到的。

//x++;这个从底层去分析:
//x++会产生一个临时变量,用来保存x+1的值,
//等到语句结束,将x+1赋值给x.
//但是语句没结束时,这个临时变量时在寄存器中保存的,一个计算结果的临时变量,
//此时是不可寻址的!!即右值。

程序分析

#include<iostream>
#include<string>

#define func(x)  _func(x,"func("#x")") 
using namespace std;

void _func(int &x,string str){ //左值值重载_func()
    cout << str << "left value !"<<endl;
    return ;
}

void _func(int &&x,string str){ //右值重载_func()
    cout << str << "right value !"<<endl;
    return ;
}
int main(){
    int x = 3;
    int y = 4;
    func(123);
    func(x++);
    func(++x);
    func(x*3);
    func(x*=3);
    func(y/4);
    func(y/=4);
    return 0;
}

输出结果为:

func(123)right value !
func(x++)right value !
func(++x)left value !
func(x*3)right value !
func(x*=3)left value !
func(y/4)right value !
func(y/=4)left value !

左值引用和右值引用

什么是左值引用和右值引用?

  • 什么是引用?

引用表示为符号“&”;
引用就是用另外的名称来索引到该变量。

左值引用

左值引用得到的就是还是一个左值

#include<iostream>
using namespace std;
int main(){
    int a = 10;
    int &b = a;
    cout << b << endl; //输出为10
    b = 5;
    cout << a << endl; //输出为5
    cout << &a << " " << &b << endl; //a和b的地址相同。
    return 0;
}

分析:

其中a和b都是左值,他们都是一个变量,且都是表示相同地址上存放的某个int类型的数。
且此时输出a和b的地址是一样的。

右值引用 (important!!!)

右值引用的使用常常在自定义类中,可以查看该博文去理解

右值引用操作符为 “&&”;
右值引用得到的是一个左值。
右值引用通常将一个临时变量拿过来用。
右值引用最主要的功能是解决的是自定义类重复构造冗余的问题。

下面三种情况就告诉你什么时右值引用?为什么要有右值引用?

  • 未使用右值引用时且不去承接返回值
//"test2.cpp"
#include<iostream>
using namespace std;

class A{
    int x;
    public:
    A(int x = 0):x(x){
        cout << this << ":default constructor"<<endl;
    }
    A(const A&a):x(a.x){
        cout << this << ":copy constructor"<<endl;

    }
    A operator+(const A& a){
        return A(x+a.x);
    }
    ~A(){
        cout << this << ":destructor"<<endl;
    }
};

int main(){
    A a(1),b(3);
    a+b;

    cout << "====================="<<endl;
    return 0;
}

通过关闭返回值优化g++ test2.cpp -fno-elide-constructor ,可以看到结果:

0x7fffbe1e127c:default constructor   //A a(1)
0x7fffbe1e1280:default constructor   //A b(3)
0x7fffbe1e1244:default constructor   //A(a.x+b.x)
0x7fffbe1e1284:copy constructor      //return A(a.x+b.x)->返回值会调用拷贝构造给承接a+b的变量A。代码中没有承接到a+b,会立马构析。
0x7fffbe1e1244:destructor
0x7fffbe1e1284:destructor
=====================   //程序结束后构析
0x7fffbe1e1280:destructor
0x7fffbe1e127c:destructor
  • 使用对象A直接去承接返回值
int main(){
    A a(1),b(3);
    A c = a+b;   //此时用A类对象C承接返回值。

    cout << "====================="<<endl;
    return 0;
}

关闭返回值优化,得到结果:

0x7ffd08697558:default constructor
0x7ffd0869755c:default constructor
0x7ffd08697524:default constructor  //A(a.x+b.x)
0x7ffd08697564:copy constructor  //return A(a.x+b.x)的临时对象
0x7ffd08697524:destructor  ~A(a.x+b.x)
0x7ffd08697560:copy constructor  //A C = (return A(a.x+b.x)) 拷贝构造
0x7ffd08697564:destructor
=====================
0x7ffd08697560:destructor
0x7ffd0869755c:destructor
0x7ffd08697558:destructor
//可以看到产生大量的拷贝构造,临时变量我没有救火,卫视拷贝了一个拿来用。
  • 使用右值引用且承接返回值
int main(){
    A a(1),b(3);
    A &&c = a+b;  //右值引用

    cout << "====================="<<endl;
    return 0;
}

关闭返回值优化,得到结果:

0x7ffc22247b74:default constructor
0x7ffc22247b78:default constructor
0x7ffc22247b44:default constructor
0x7ffc22247b7c:copy constructor
0x7ffc22247b44:destructor
=====================
0x7ffc22247b7c:destructor
0x7ffc22247b78:destructor
0x7ffc22247b74:destructor
//可以发现return A(a.x+b.x)产生的临时对象直接被C用了,没产生多余的拷贝构造。

右值引用就是把右值变成左值,通常实在C++返回值上,对于自定子类的重复拷贝做了重要改善,大大提高了C++的效率。
右值引用的概念是C++中的重要概念!!!!。

左值和右值的转换

左值变右值

  • 通过move(class value)函数

move()可以通过man手册查看。

  • 通过通用转换 forward<B&&>
    • 通过引用const &

变成只读,也是不能放在等号左边

右值变左值

  • 通过右值引用&&

  • 通过通用转换 forward<B&>

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-05-06 10:54:21  更:2022-05-06 10:55:17 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/21 1:34:45-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码