AI智能
改变未来

C++ 左值、右值、左值引用、右值引用


一、左值右值

1.1 定义

在C++中有几个晦涩的概念:左值、右值、泛左值、纯右值、将亡值

泛左值=左值+将亡值; 右值=纯右值+将亡值; 我们可以发现将亡值既属于泛左值又属于右值;

这些分类是由于它们具有不同性质而命名的,但其实我们只需要掌握左值和右值的概念就已经足够了。

这5种值类型我总结了一张表格,如下:

首先这几个名词用来形容一个表达式,在C++中,一切表达式都必然属于左值、将亡值、纯右值中的一种。而右值=将亡值+纯右值,所以我们又可以说一切C++表达式都必然要么是左值要么是右值。

从性质上来看:

  • 只有左值可以取地址、可以作为等号左边的操作数;不具有该性质的就必然是右值。
  • 左值和将亡值都具有多态性质;不具有该性质的就是纯右值了。

 

1.2 举例

用是否可以取地址来验证表达式是左值还是右值:

#include <utility>#include <string>using namespace std;string &f1(string &a) {return a;}string &&f2() {string a;return move(a);}string f3() {return "";}int main() {string s("hello");printf("%p\\n", &f1(s)); //f1(s)是左值,可以取地址// printf("%p\\n", &f2()); //f2()是将亡值,不能取地址// printf("%p\\n", &f3()); //f3()是纯右值,不能取地址int a = 1;printf("%p\\n", &++a); //前置自增是左值,可以取地址// printf("%p\\n", &a++); 后置自增是右值,不能取地址printf("%p\\n", &"hello"); //字符串字面值是左值,可以取地址// printf("%p\\n", &42); //数字字面值是右值,不能取地址}

验证将亡值的多态性

#include <iostream>struct A {virtual void f() {printf("classA\\n");}};struct B : A {void f() override {printf("classB\\n");}};int main() {static_cast<A&&>(B()).f();  //打印classB, static_cast表达式是将亡值,静态类型为A,动态类型为B,发生多态static_cast<A>(B()).f();  //打印classA, static_cast表达式是纯右值,静态类型为A,动态类型为A,未发生多态}

 

二、左值引用 右值引用

2.1 定义

在C++中引用类型与表达式之间的绑定关系有语法上的规定,如下表:

  • T&只能绑定非常量左值
  • const T&是万能引用类型,可以绑定任意值类型的表达式
  • T&&只能绑定非常量右值
  • const T&&能绑定右值类型的表达式,无论是否常量

代码验证绑定规则:

#include <utility>#include <string>using namespace std;int main() {string s1;  //非常量左值const string s2;  //常量左值string &r1 = s1;             //【非常量左值引用】可以绑定【非常量左值】// string &r2 = s2;          //【非常量左值引用】不能绑定【常量左值】const string &r3 = s1;       //【常量左值引用】可以绑定【非常量左值】const string &r4 = s2;       //【常量左值引用】可以绑定【常量左值】const string &r5 = move(s1); //【常量左值引用】可以绑定【非常量右值】const string &r6 = move(s2); //【常量左值引用】可以绑定【常量右值】string &&r7 = move(s1);      //【非常量右值引用】可以绑定【非常量右值】// string &&r8 = move(s2);   //【非常量右值引用】不能绑定【常量右值】const string &&r9 = move(s1); //【常量右值引用】可以绑定【非常量右值】const string &&r10 = move(s2); //【常量右值引用】可以绑定【常量右值】}

 

2.2 引用的作用

左值本身就是具名变量,当它被绑定给左值引用时只是起了个别名,生命周期并不会变化。

而右值本身的生命周期会在表达式结束后立即被销毁,当右值被绑定给引用时,该右值“重获新生”,它的生命周期会延长,与该引用的生命周期相同。

代码举例:

未完待续

1d45f 

2.3 需要注意的点

右值引用是个左值。(是不是很绕口?)

准确的来说,所有的引用,无论是左值引用还是右值引用,都是左值表达式。

这是因为右值引用延长了右值的生命周期,我们可以去取右值引用的地址,因此它是个左值。

代码举例:

未完待续

 

 

 

赞(0) 打赏
未经允许不得转载:爱站程序员基地 » C++ 左值、右值、左值引用、右值引用