/*
* 理解左值和右值
*
*
* 为什么要关心这个?
* 1. 有助于理解C++结构,搞明白编译器的错误和警告
* 2. C++ 11中引入了右值引用,理解左值右值是前提
*
*/
/*
* 简单的定义:
*
* 左值 - 在内存中具有可标识位置的对象
* 右值 - 任何不是左值的对象
*/
//左值的例子:
int i; // i是左值
int* p = &i; // i的地址是可标识的
i = 2; // 内存的内容改变
class dog;
dog d1; // 用户定义类型的左值
// C++代码中大多数变量是左值
//右值的例子:
int x = 2; // 2是右值
int x = i+2; // (i+2)是右值
int* p = &(i+2); // Error,地址不可标识
i+2 = 4; // Error 地址不可标识
2 = i; // Error
dog d1;
d1 = dog(); // dog()是用户定义类型的右值
int sum(int x, int y) { return x+y; }
int i = sum(3, 4); // sum(3, 4) 是右值
//右值: 2, i+2, dog(), sum(3,4), x+y
//左值: x, i, d1, p
//引用 (或者说左值引用):
int i;
int& r = i;
int& r = 5; // Error,引用不能赋值为右值(还是左值),需要可标识的地址 这里理解为5是常量 只能赋值给常量的引用。
//例外:常量左值引用可以赋值为右值
const int& r = 5; //
// 函数中的例子
int square(int& x) { return x*x; }
square(i); // OK
square(40); // Error
//解决方法:
int square(const int& x) { return x*x; } // square(40) and square(i) work
/*
* 左值可以用来生成右值
*/
int i = 1;
int x = i + 2;
int x = i;
/*
* 右值可以用来生成左值
*/
int v[3];
*(v+2) = 4;
/*
* 误解1:函数或运算符总是产生右值
*/
int x = i + 3;
int y = sum(3,4);
int myglobal ;
int& foo() {
return myglobal;
}
foo() = 50;
// 更常见的例子:
array[3] = 50; // 操作符[] 几乎总是返回左值
/*
* 误解2:左值都是可以修改的
*
*/
const int c = 1; // c是左值
c = 2; // Error, 但是c不能被修改
/*
* 误解3:右值不能被修改
*/
i + 3 = 6; // Error,内置类型的确不行
sum(3,4) = 7; // Error
// 对于用户定义类型不成立
class dog;
dog().bark(); // dog()是右值,bark() 可能修改dog对象的状态
/*
* 总结
*
* 1. 每个C++表达式生成一个左值或右值
* 2. 如果表达式有一个可以标识的内存地址,则它是左值;否则,是右值
*/