左值和右值
1.在C++11中可以取地址的、有名字的就是左值,反之,不能取地址的、没有名字的就是右值(将亡值或纯右值)。左值绝大多数时候在等号左边,右值在右边,但这并不总是对的。
例如:int i=10 ;变量i是一个在内存中有位置的实际变量,数字10没有存储空间,没有位置,所以我们就不能写成int 10=i,因为10没有位置,我们不能在10中存储数据。但是,我们可以让另一个变量int a=i;这样一个左值就等于了另一个左值。
2.一个对象被当作左值时,使用的是它的地址,被用作右值时,使用的是它的内容(值)。
左值引用
1.左值引用通常称为“引用”,引用是为对象起的别名,必须被初始化,和变量绑定在一起,且将一直绑定在一起。
可以通过&获取左值引用
type &引用名=左值表达式
可以把引用绑定在左值上,而不能绑定在要求转换的表达式、字面常量或是返回右值的表达式。
例如:
int i=10;
int &j=i; //正确
int &j=i*2; //错误,i*2是一个右值
const int &j=i*2; //正确,可以将一个const引用绑定在右值上
右值引用
1.右值引用就是必须绑定到右值上的引用
我们通过&&获取右值引用
type &&引用名=右值表达式
右值引用有一个重要的性质——只能绑定到将要销毁的对象上。
例如:
int &&j=i; //错误,i是一个左值
int &&j=i*2; //正确,i*2是一个右值
2.右值不仅只是字面量,也可以是函数结果。
#include<iostream>
int GetValue() {
return 10;
}
int main() {
int i=GetValue(); //正确
GetValue()=5; //编译错误,因为GetValue()是一个右值
}
要解决上面的编译错误情况,就要用到左值引用,让函数的返回值为左值。
#include<iostream>
int& GetValue() { //左值引用,函数返回值为左值
static int value=10;
return value;
}
int main() {
int i=GetValue(); //正确
GetValue()=5; //正确
}
扩展
1.如果一个函数,它有一个值,我们可以用左值或右值来调用它。
#include<iostream>
void SetValue(int value) {
}
int main() {
int i=10;
SetValue(i);
SetValue(10); //临时值
}
2. 注意,下面为错误代码:
#include<iostream>
void SetValue(int& value) {
}
int main() {
int i=10;
SetValue(i);
SetValue(10); //错误,不能用左值来引用右值
}
要解决上述情况,我们可以改用const引用(与右值兼容),const引用既可以接收左值,也能接收右值。
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="wang";
std::string lastname="wenhao";
std::string fullname=firstname+lastname;
PrintName(fullname); //错误 ,右值引用不能传递左值
PrintName(firstname+lastname);
}
4.特殊情况:下面代码中的第一个重载函数为const引用,既可以接收左值,又可以接收右值,但由于存在第二个重载函数为右值引用,所以当传入参数为右值时,会优先调用第二个重载函数。
运行结果为: [lvalue]:wangwenhao
[rvalue]:wangwenhao
#include<iostream>
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="wang";
std::string lastname="wenhao";
std::string fullname=firstname+lastname;
PrintName(fullname);
PrintName(firstname+lastname);
}