C++语法学习笔记十九:左值-右值-左值引用-右值引用-move

实例代码:


#include <iostream>
#include <string>
#include <vector>

using namespace std;


int main() {
	//一:左值和右值
	int i0 = 20; //对象:一块内存区域;
	i0 = 20;
	//左值: “能用在赋值语句等号左侧的东西”,它能够代表一个地址。
	//右值: “不能作为左值的值就是右值”;右值不能出现在赋值语句中等号的左侧。
	//结论:
	//C++ 的一条表达式,要么就是右值,要么就是左值,不可能两者都不是。
	//左值有的时候能够被当做右值使用。
	i0 = i0 + 1;  // i0是个左值,不是个右值,虽然它出现在了等号右边。
				// i0用在等号右边的时候,我们说i有一种右值属性(不是右值)。
				// i0出现在等号左边,用的是i代表的内存中的地址, 我们说i 有一种左值属性。
	//一个左值 它可能同时具有左值属性和右值属性。

	//用到左值的运算符有哪些:
	//a) 赋值运算符
	//int a;
	//prinf("%d\n", a = 4); // 4
	//整个赋值语句的结果仍然是左值。
	//(a = 4) = 8;
	
	//b) 取地址 &
	int a = 5; // 变量就是左值
	&a; //&8;

	//c) string vector 下标[]都需要左值。迭代器。
	string abc = "I Love China!";
	vector<int>::iterator iter;

	//...
	iter++; iter--; // 9--;
	abc[0];

	//d) 通过看一个运算符在一个字面值上能不能操作,我们就可以判断运算符是否用到的是左值。
	//i0++; 5++;

	//左值表达式 就是左值, 右值表达式 说的就是右值。
	//左值: 代表一个地址,所以左值表达式的求值结果,就得是一个对象,就得有地址。
	// 求值结果为对象的表达式,不代表 一定是左值,具体在分析。
	//100 :它显然是个右值。

	//二:引用分类
	int value = 10;
	int &refval = value;
	refval = 13; // value = 13;

	//三种形式的引用
	//(1) 左值引用(绑定到左值);
	//(2) const引用(常量引用),也是左值引用。我们不希望改变值的对象。
	const int &refval2 = value;

	//refval2 = 18;
	//(3) 右值引用(绑定到右值):它是个引用。
	int &&refrightvalue = 3; // 绑定到一个常量。
	refrightvalue = 5;

	//三:左值引用
	//引用左值,绑定到左值上。
	char *p = nullptr; //指针有空指针的说法。
	//没有空引用的说法,所以左值引用初始化的时候就绑定左值
	int a1 = 1;
	int &b{ a1 }; // b绑定到a
	//int &c; //错误,引用必须要初始化
	//int &c = 1; //不可以,左值引用不能绑定到右值,必须绑定到左值。
	const int &c = 1; // const 引用可以绑定到右值,所以const引用特殊。
	int tempvalue = 1; //临时变量
	const int &d = tempvalue;

	//四:右值引用: 就是引用右值,也就是说,绑定到右值。
	//必须是绑定到右值的引用。
	//&& ,希望用右值引用来绑定一些即将销毁的或者是一些临时的对象上。
	//右值 引用 也是 引用。
	int &&refrightvalue1 = 3; //右值引用大家理解成一个对象的名字。
	refrightvalue1 = 5;
	//int value11 = 10;
	//int &refval11 = 5;
	//能绑定到左值上的引用,一般都不能绑定到右值。
	//int value22 = 5;
	//int &&refrightvalue = value22; //右值引用也绑不到左值上。

	string strtest{ "I Love China!" };
	string &r1{ strtest }; //可以,左值引用绑定左值
	//string &r2{ "I love China" }; //不可以,左值引用不能绑定到临时变量。临时变量被系统当做右值
	const string &r3{ "I love China" }; //可以,创建个临时变量,绑定到左值r3上去。
					//const引用不但可以绑定到右值,还可以执行到string的隐式类型转换并将所得到的值放到string临时变量中;
	//string && r4 {strtest}; //不可以,右值引用不能绑定到左值
	string &&r5{ "I love China" }; //可以,绑定到一个临时变量,临时变量的内容  "I love China"
	int i = 10;
	int &r6 = i; //正确 左值引用
	//int &&r7 = i; //不可以,不能将右值引用绑定到左值上。
	int &&r8 = i * 100; //可以,右值引用绑定到右值
	//int &r9 = i * 100;// 左值引用不能绑定到右值。
	const int &r10 = i * 100; //绑定到右值
	int &&r11 = i * 100; //正确。右值引用绑定到右值

	//总结:返回左值引用的函数,连同赋值,下标,解引用和前置递增减运算符(--i),都是返回左值表达式的例子;我们可以将一个左值引用绑定到这类表达式的结果上。
	//返回非引用类型的函数,连同算术,关系,位以及后置递增运算符(i--),都生成右值,不能将一个左值引用绑定这类表达式上,
	//但是我们可以将以const的左值引用或者一个右值引用绑定到这类表达式上。

	//++i; //左值表达式。++i直接给变量 i+1, 然后返回i本身
	//因为i是变量,所以可以被赋值。
	int i1 = 100;
	(++i1) = 199; // i 被赋值成199了。

	//i++ : 先用后加,为什么就是右值表达式呢?
	//i++ 先产生一个临时变量 tempi, 记录i(tempi = i) 的值用于使用的目的,再给i+1, 接着返回这个临时变量,临时变量这个东西,右值
	//(i++) = 199; //语法错误

	int i2 = 1;
	int &&r12 = i++; //成功绑定右值,但是此后r12的值和i没有关系。
	//i += 5;
	//int &r13 = i++; // 不可以,不能绑定到右值表达式上去
	int &r14 = ++i; //r14绑到i , r14就变成i的别名了。
	i += 5;
	//int &&r15 = ++i; // 不可以,右值不能绑定左值表达式


	//重点强调:
	//(1) r12虽然是右值引用(绑定到了右值),但是r12本身它是左值(你要把r12看成一个变量)。因为它在=左边呆着
	int &r16 = r12; // r12是左值。
	//int &&r17 = r12;
	//(2) 所有变量,看成左值,因为他们是有地址的。而且你用右值引用也绑定不上。
	//int &&r11 = i; //失败。
	//(3) 任何函数里边的形参都是左值,void f(int i , int &&w) : w是右值引用,但w本身是左值。
	//(4) 临时对象都是右值。下节详细讲解临时对象。

	//(4.1) 右值引用的引入目的
	//a) C++11 引入,&&,代表一种新数据类型,引入新数据类型肯定有目的。
	//b) 提高程序运行效率。把拷贝对象变成移动对象来提高程序运行效率。
	//c) 移动对象如何发生。&&(应付移动构造函数, 应付移动赋值运算符用的) &

	//五: std::move函数
	//C++ 11标准库里的新函数。
	//std::move :移动。实际上这个函数根本就没有做移动的操作。
	//std::move 的能力只有一个:把一个左值强制转换成一个右值。带来的结果就是我一个右值可以绑上去了;
	int i10 = 10;
	//int &&ri20 = i10; //不可以
	int &&ri20 = std::move(i10); // 可以, 把一个左值转成一个右值,这就是move的能力;
	i10 = 20;
	ri20 = 15; //ri20就代表i10了。

	int &&ri30 = 100;
	//int &&ri31 = ri30;
	int &&ri31 = std::move(ri30); //绑定
	ri30 = 68;
	ri31 = 46;

	string st = "I Love China!";
	const char *p1 = st.c_str();
	string def = std::move(st); //string里的移动构造函数把st的内容移动到了def中去了。而不是std::move干的;
	const char *q = def.c_str();
	std::move(st);

	string &&rdef = std::move(st);
	st = "abd";
	rdef = "ffghshg";

	//六: 左值右值总结说明
	int &&ri32 = 67;


	system("pause");
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值