前言
晚上在电梯里刷知乎的时候,刷到move,于是便好奇多搜索点相关知识,其中左值和右值可算看懂了点了,于是趁着还没睡觉总结一波
内容
左值和右值网上很多通俗的说法是,左边的是左值,右边是右值,比如
代码语言:javascript复制int a = 5;
a是左值,5是右值,这也是对的,但是呢,他不完全对
代码语言:javascript复制int a = 10;
10 = a;
你会发现第二行10=a这就会报错
再比如
代码语言:javascript复制int func()
{
return 10;
}
a = 10; // yes
a = func(); // yes
func() = a; // error
再比如
代码语言:javascript复制int& func()
{
static int test = 10;
return test;
}
a = 10; // yes
a = func(); // yes
func() = a; // func()是左值
你看懂了吗,只有它返回的是一个地址才能是左值,而之前直接return 10;这个10在内存中没有任何作用
我们再看
代码语言:javascript复制void func(std::string& name)
{
std::cout << name << std::endl;
}
int main()
{
std::string firstName = "Neil";
std::string secondName = "Zhu";
std::string name = firstName secondName;
func(name);
func(firstName secondName);//编译器提醒这不是一个左值
}
此时编译器提醒func(firstName secondName);不是一个左值,因为虽然firstName和secondName是左值,但是他们两个临时形成的新字符串firstName secondName并不是一个有地址的东西,属于临时中间产生的而已,所以报错
但把代码改为:
代码语言:javascript复制void func(const std::string& name)
{
std::cout << name << std::endl;
}
int main()
{
std::string firstName = "Neil";
std::string secondName = "Zhu";
std::string name = firstName secondName;
func(name);
func(firstName secondName);
}
我们发现就是在func里面用了const,这就可以了,虽然参数还是左值引用,但是新字符串firstName secondName这个临时右值也可以传进去
这就是你能看到为什么C 中有时候会有常量引用,因为它兼容临时的右值和实际存在的左值
再看一个
代码语言:javascript复制void func(std::string&& name)
{
std::cout << name << std::endl;
}
int main()
{
std::string firstName = "Neil";
std::string secondName = "Zhu";
std::string name = firstName secondName;
func(name); // error
func(firstName secondName);
}
这时候func(name);会报错,因为参数是个右值引用,但是name是左值,所以没办法传进去
总结下就是左值引用在const时候可以绑定临时的右值和左值 但是右值引用只能绑定右值
这时候我们整合下代码,重载两个函数
代码语言:javascript复制void func(const std::string& name)
{
std::cout << name << std::endl;
}
void func(std::string&& name)
{
std::cout << name << std::endl;
}
int main()
{
std::string firstName = "Neil";
std::string secondName = "Zhu";
std::string name = firstName secondName;
func(name);
func(firstName secondName);
}
你会发现代码都正确,现在即使左值引用加了const,临时右值也可以穿进去,但其实firstName secondName走的还是右值引用自己的函数
下次再谈谈移动语义,看知乎的回答,move的作用是转移所有权,比如vector里面存了一些内容,之前直接复制的话,就很浪费空间,因为要一个个把内容复制过去,现在可以用move,直接把vector1的内容地址直接告诉vector2,让vector的指针直接指向这片空间的地址,但要注意的是之前vector1指针就空了