C++学习笔记 49 左值右值

一、什么是左值右值

  1. 很多人称左值是有地址的值(located value), 不完全正确。
  2. 左值是有某种存储支持的变量,右值是临时值。
  3. 左值引用仅仅接受左值,除非是用const;
  4. 右值引用仅仅支持右值,

随着这个系列的深入,特别是移动语义的情况,我们会越来越清楚地知道,为什么它很重要了。

#include<iostream>
#include<string>

int GetValue() {
	return 10;
}

int& GetValueRef() {
	static int value = 10;
	return value;
}

void SetValue(int value) {

}

//只支持接收左值参数 (非常量,可modify)
void SetValueRefOnlyLeftValue(int& value) {

}

//同时持接收左值和右值两种参数,(常量,不可modify)
void SetValueRefBothLeftRightValue(const int& value) {

}

void testLeftRightValue01() {
	int i = 10;

	//错误 '=': left operand must be l-value
	//10 = i;

	int a = i;

	//右值也可以是一个带返回值的函数,是临时的值,没有位置,没有存储空间,只是返回一个值
	int k = GetValue();

	//❌️ '=': left operand must be l-value
	//GetValue() = i;

	//编译可以通过,左值引用
	GetValueRef() = 5;


	SetValue(i);
	SetValue(10);

	
	SetValueRefOnlyLeftValue(i);
	//'void SetValueRefOnlyLeftValue(int &)': cannot convert argument 1 from 'int' to 'int &'
	//SetValueRefOnlyLeftValue(10);

	//不能将右值赋给左值引用,所以左值引用的,只能是左值
	//'initializing': cannot convert from 'int' to 'int &'
	//int& b = 10;

	//但是左值引用如果加上了const的话,则可以
	
	const int& c = 20;
	//这是一个特殊规则,它是一种变通方法,实际情况是,编译器可能会用你的存储创建一个临时变量,然后把它赋值给那个引用
	//所以,实际上它不可避免的创建了一个左值,但也同时支持了左值和右值:
	int temp = 10;
	const int& cc = temp;
}

//Only support left value
void PrintNameLeftValue(std::string& name) {
	std::cout << "[lvalue] " << name << std::endl;
}

//Support both left and righ value
void PrintNameBothValue(const std::string& name) {
	std::cout << "[lrvalue] " << name << std::endl;
}

//有了右值引用,我们现在有了一种方法来检测临时值,并对它们做一些特殊的事情(通过方法的重载,可以将leftValue(), BothValue(), RightValue() 方法同名重载,)
//这非常有用,尤其是在移动语义上
//如果我们传入的事一个临时对象,我们就不需要关心它们是否活着,是否完整,是否拷贝。我们可以轻松的触及它的资源,给到特定的对象,或者其它地方使用它们,因为我们知道它是暂时的,它不会存在很长时间。
void PrintNameRightValue(std::string&& name) {
	std::cout << "[rvalue] " << name << std::endl;
}

void testLeftRightValue02() {
	std::string firstName = "Yan";
	std::string secondName = "Chernikov";
	std::string fullName = firstName + secondName;

	PrintNameLeftValue(firstName);
	PrintNameLeftValue(secondName);
	PrintNameLeftValue(fullName);
	//A non-const reference may only be bound to an lvalue
	//PrintNameLeftValue(firstName + secondName);

	//这就是为什么你会看到很多C++写的常量引用,因为它们兼容临时的右值和实际存在的左值变量
	PrintNameBothValue(firstName + secondName);

	//所以很明显,有一种方法来检验某值是否是左值:写一个非常量的左值引用,因为左值引用只能接受左值
	//void PrintName(std::string & name) {}

	//我们有没有办法写一个函数,只接收临时对象?是的,为此我们需要一个右值引用的东西
	//右值引用和左值引用一样,只不过要用两个&&,

	//错误❌️:You cannot bind an lvalue to an rvalue reference
	PrintNameRightValue(fullName);
	PrintNameRightValue(firstName + secondName);
}

int main() {
	//testLeftRightValue01();
	testLeftRightValue02();
	std::cin.get();
}
posted @ 2026-01-02 17:02  超轶绝尘  阅读(1)  评论(0)    收藏  举报