[85] 左值右值(移动语义前篇)

左值和右值(L值和R值)

基础概念

int RGetValue()
{
	return 10;
}
int& LGetValue()
{
	static int value = 10;
	return value;
}
int main()
{
	//1.很多时候就像这个,左值就好像是在等号的左边
	//右值在等号的右边,但这并不是一个完整的事实(实际上也不是这样)
	//在这个例子中,i在内存中有地址,而10只是一个值,没有存储空间,直到它分配给L值
	//所以,你不能给R值赋值。
	int i = 10;
	
	//2.这俩个a,和i都是左值。
	int a = i;

	//3.在这个例子中,RGetValue返回的也是一个R值,因为即使返回一个int,它在内存中也没有位置。
	//在这里我们做的是,获得一个右值,将该临时值赋值并存储为L值。
	int i = RGetValue();
	
	//在这个例子中,我们在函数返回的就是一个左值了,(我们定义了一个静态的函数对象的引用并返回)
	LGetValue() = 5;
}

关于引用

1、左右值都可以做参数

void SetValue(int value)
{

}

int main()
{
	int i = 10;
	//在这个带参数的例子中,我们可以用L值做参数,也可以用R值做参数
	//但是在用R值做参数的情况下,当函数实际被调用时,这个R值将会被用来创建L值
	SetValue(i);
	SetValue(10);
}

2、左值参考

void SetValue(int& value)
{

}

int main()
{
	int i = 10;
	//一旦调用函数的参数是一个左值引用,这里就会立即出现一个错误
	SetValue(10);
}

[85] 左值右值(移动语义前篇)

在这个错误提示中,有一个很特殊的规则,就是const。
当我们试图写int& a = 10;,这是不被允许的,但是如果我们写const int&a = 10;,这样就可行了。这个特殊的规则实际上编译器做的事情可能就像是

	int temp = 10;
	const int& a = temp;

实际上这只是避免去创建一个L值,而是仅仅能都支持L值和R值
所以如果我们想让开始的左值引用代码生效,我们可以这样改动它

//注意,我们在这里让参数等于const int&
void SetValue(const int& value)
{

}
int main()
{
	int i = 10;
	//这样就都支持了!
        SetValue(i);
	SetValue(10);
}

3、右值引用
如果我们想写一个仅接受临时对象的函数呢,我们就需要所谓右值引用&&了!

void PrintName(std::string&& name)
{
	std::cout << name << std::endl;
}

int main()
{
	std::string firstName = "Yan";
	std::string lastName = "Chernikov";	
	std::string fullName = firstName + lastName;

	PrintName(firstName);
}

[85] 左值右值(移动语义前篇)
这是有意义的,因为我们可以编写此函数的重载

void PrintName(const std::string& name)
{
	std::cout << "[lvalue]" << name << std::endl;
}
void PrintName(std::string&& name)
{
	std::cout << "[rvalue]" << name << std::endl;
}

int main()
{
	std::string firstName = "Yan";
	std::string lastName = "Chernikov";
	
	std::string fullName = firstName + lastName;

	PrintName(fullName);
	PrintName(firstName + lastName);
}

[85] 左值右值(移动语义前篇)
这非常有用,不过是在另一个主题“移动语义”上啦。

[85] 左值右值(移动语义前篇)

上一篇:Web测试与APP测试有哪些异同?


下一篇:Android项目迁移到Androidx的问题解决