头图

来看一行简单的代码:

int a = 10;

这行代码,"=" 左边就是左值,"="右边的则为右值,那他们到底有什么不同呢?

如果是Java、PHP等后端同学,会称以左边的"a"为变量,右边的"10"为字面量,而到了C++这里,我们就需要对他理解更多一点。
这行代码运行起来,是在系统内存中申请了一块空间,命名为"a",然后把"10"这个值装入了这个单内存空间中,内存中的空间是有地址的,并且和"a"这个名字绑在一起,当我们提到"a",就能知道他所代表的内存地址,这也是所谓的"可寻址"。

在C++中,每个表达式都具有一个值和一个类型。左值和右值描述了表达式的可寻址性和持久性。

首先,让我们来看一下左值的概念。左值是指可以被取地址的表达式,或者说具有标识符的表达式。左值表示一个内存位置,它具有持久性,可以在程序的不同部分访问和修改。简而言之,左值可以出现在赋值运算符的左边。

下面看看左值的特点:

int x = 10;     // 'x' 是一个左值,可以被赋值
int* p = &x;    // '&x' 是一个左值,可以取其地址
int arr[5];     // 'arr' 是一个左值,可以被访问和修改

接下来,我们来看一下右值的概念。右值是指不可被取地址的表达式,或者说临时生成的表达式。右值表示一个临时的值,它通常只能用于赋值或传递给函数,没有持久性。简而言之,右值可以出现在赋值运算符的右边。

以下看看右值的特点:

int a = 5;              // '5' 是一个右值
int b = a + 3;          // 'a + 3' 是一个右值
int* ptr = new int(10); // 'new int(10)' 返回一个右值

需要注意的是,C++11引入了右值引用的概念,即可以对右值进行引用的类型。右值引用允许我们更有效地管理资源,如移动语义和完美转发。

综上所述,左值表示持久的可寻址表达式,而右值表示临时的不可寻址表达式。理解左值和右值的概念对于理解C++中的赋值、函数调用和参数传递等操作是非常重要的。


那么,一个函数返回值,应该是左值还是右值?

当一个函数被调用时,它会在栈上创建一个新的帧来存储该函数的局部变量、参数以及其他信息。该帧在函数返回时销毁。

因为函数返回值通常是通过寄存器或者特殊寄存器(如eax)返回的,它们的地址在栈帧被销毁后就不能再访问了。所以不能直接对函数返回值取址。

但是,如果你需要返回一个指向已经存在的内存块的指针,然后在函数外使用该指针访问内存块,那么是可以的。例如:

int* foo() {
    int x = 10;
    return &x;
}

int main() {
    int* p = foo();
    std::cout << *p; // undefined behavior
    return 0;
}

上述代码中的foo()函数返回了一个指向局部变量x的指针。这会导致undefined behavior,因为x在函数返回时就被销毁了,所以p指向的内存块中可能包含任意的值。

所以,不能直接对函数返回值取址,函数返回值是一个右值。
但如何函数返回的是指向已经存在的内存块的指针,即不是函数内定义的东西,那么取址是没有问题的。


Totn
10 声望5 粉丝

幼稚也没关系,去实践,去经历,去思考!