具有以下特征:
那么哪些都是左值呢?查了相关资料,做了些汇总,基本覆盖了所有的类型:
class Teacher72{
public:
Teacher72() {
};
Teacher72(int age):mage(age) {
};
int mage;
int getAge() {
return mage;
}
};
int & func72() {
int a = 90;
return a;
}
int func73() {
return 0;
}
void main() {
//
cout << "左值" << endl;
//变量名、数据成员名
int a = 1;
typedef int(*FUNCTYPE)();// 定义一种类型,函数指针
FUNCTYPE aa = func73;
//返回左值引用的函数调用
func72() = 90;
//由赋值运算符或复合赋值运算符连接的表达式,如(a = b, a -= b等)
int a1 = 89;
int b1 = 987;
a1 = b1 = 888;
cout << "a1 = " << a1 << " b1 = " << b1 << endl;
a1 += b1;
cout << "a1 = " << a1 << " b1 = " << b1 << endl;
//解引用表达式*ptr
int *p1 = &a1;
*p1 = b1;
cout << "*p1 = " << *p1 << endl;
//前置自增和自减表达式(++a, ++b)
int a2 = 8;
++a2 = 8989898;// ++a 的理解是:a2 = a2+1; 然后将a2 return 出去,然后给a2 = 8989898,因为是将a return出去的,因此可以给a赋值
cout << "a2 = " << a2 << endl;
//成员访问(点)运算符的结果
Teacher72 tea;
tea.mage = 88;
//由指针访问成员(->)运算符的结果
Teacher72 * ptea = &tea;
ptea->mage = 909;
//下标运算符的结果([])
int arr[3] = { 10,20,30 };
arr[0] = 909090;
cout << "范围for语句 start" << endl;
for(auto in:arr)
{
cout << in << endl;
}
cout << "范围for语句 end" << endl;
//字符串字面值("abc"), 为什么字符串字面值 可以做为左值呢?
"abc" ;//这个是个左值,怎么理解呢?
//字符串字面值为左值,例如:hello, world,
//因为字符串字面值在内存中就是按字符数组保存的,有实实在在的地址。
const char ss[6] = "sssss"; //在内存中是按照const char []数组保存的,因此有实实在在的地址的
//但是这个当做左值有啥用呢?左值引用的时候吗?
//"abc" = 0X898987; build error
//"abc" = "NMN"; build error
}
在前面有提过,自C++11开始,纯右值(pvalue, pure ravlue)相当于之前的右值,那么什么是纯右值呢?
为了加深对右值的理解,下面的例子是常见的纯右值:
nullptr;
true;
1;
int fun();
fun();
int a = 1;
int b = 2;
a + b;
a++; 先给一个临时变量 int tempa = a; 将临时变量tempa return 出去,然后再给a = a+1;因为这时候return出去的是的tempa,是个临时变量,因此是个右值。
b--;
a > b;
a && b;
是指可以移动的表达式。prvalue和xvalue都是rvalue,具体的示例见下文。
rvalue具有以下特征:
临时变量
//左值引用,和const 左值引用
//等号右边需要是 左值
//左值引用 绑定左值后, 一荣俱荣,一损俱损。一改都改
void main() {
//左值引用举例一
int a = 10;
int &b = a; // b是左值引用,a 是左值
cout << "a = " << a << " b = " << b << endl;
b = 80;
cout << "a = " << a << " b = " << b << endl;
///左值引用举例2
std::string str1 = "abc";
std::string &str2 = str1;
str2 = "ccc";
cout << "str1 = " << str2 << " str2 = " << str2 << endl;
//const左值引用 举例,const 左值引用不允许改动值
int c = 10;
const int &d = c;
cout << "c = " << c << " d = " << d << endl;//结果为10,10
//d = 20; build error
c = 90;
cout << "c = " << c << " d = " << d << endl;//结果为90,90,一荣俱荣,一损俱损
}
//右值引用,
//等号右边需要是 右值
//一旦绑定,一荣俱荣,一损俱损
//右值引用也是引用,目的是延长即将销毁变量的声明周期
//右值引用使用 && 表示
void main() {
int &&aaa = 90;
cout << "aaa = " << aaa<
int &&rrb3 = 898998; // 正确,898998为右值,rrb3为右值引用,但是rrb3本身是左值
int &cccccc = rrb3;// 将左值rrb3 赋值给 cccccc这个左值引用上
cout << cccccc << endl; //结果为898998
cccccc = 9;
cout << cccccc << " " << rrb3<< endl; //结果为9 he 9
该函数没有任何move的操作,作用是:把一个左值变成右值。目的是为了 移动构造函数做准本,下一章节会记录这个 移动构造函数
move(T t)执行后,t就不要使用,虽然在vs2017 即使使用了也没有问题,但是这个是不稳定的,随时有可能出现问题。
//std::move(T t)函数
//该函数没有任何move的操作,作用是:把一个左值变成右值。目的是为了 移动构造函数做准本,下一章节会记录这个 移动构造函数
//move后,之前的参数不能再用,我们如下的例子还是用了 bb1,这是不对的,虽然结果是对的。
int aa1 = 89;
int &bb1 = aa1;//bb1是左值引用, aa1是左值
int &&cc1 = move(bb1);//将bb1通过move函数变成了 右值引用
cout << "aa1 = " << aa1 << " bb1 = " << bb1 << " cc1 = " << cc1 << endl;//结果都是89
aa1 = 99;
cout << "aa1 = " << aa1 << " bb1 = " << bb1 << " cc1 = " << cc1 << endl;//结果都是99
bb1 = 109;//不要这么用,bb1 是左值引用,已经被move函数操作过了,因此不要用
cout << "aa1 = " << aa1 << " bb1 = " << bb1 << " cc1 = " << cc1 << endl;//结果都是109
cc1 = 119;
cout << "aa1 = " << aa1 << " bb1 = " << bb1 << " cc1 = " << cc1 << endl;//结果都是119
//move函数容易出现的误会。
string st1 = "dfe";
string st2 = move(st1);//在move之后,st1中的字符串已经不存在了,
// 看起来好像是move函数将st1中的字符串转移到st2中去了,实际上不是的,
// 是string里的移动构造函数,把st中的内容转移到st2中了
// 注意后,move(st1),将st1从左值变成右值,
string st3 = "abc";
string && st4 = move(st3);//将st3通过move转成右值,然后给 右值引用st4 上绑定st3,之后,st3和st4穿同一条裤子,一个改动,另一个改动。
//注意的是, st3在move之后,不应该再次使用
cout << "断点在这里" << endl;
}