左值与右值的定义
在 C++(包括 C)中,所有的表达式和变量要么是左值,要么是右值。通俗地讲,左值就是非临时对象,也就是那些可以在多条语句中反复使用的对象。
所有的变量都满足这个定义,因为它们可以在多条代码中被使用,因此都是左值。而右值指的是临时对象,它们只在当前语句中有效,例如立即数、未命名对象等。
需要注意的是:出于安全性的考虑,具名变量即使被声明为右值类型,也不会被当作右值使用,而要借助 std::move 函数(后文会详细说明)。
右值引用的作用
右值引用主要实现了两件事:语意转移 和 完美转发。
语意转移 std::move
使用语意转移的好处在于:消除了无意义的拷贝工作,效率大大提升。
编译器只有在面对右值引用时才会调用转移构造函数和转移赋值函数,而所有命名对象本身都只能是左值引用。如果我们已知一个命名对象不再被使用,想要对它调用转移构造函数或转移赋值函数,也就是把一个左值引用当作右值引用来使用,该怎么办?标准库为此提供了 std::move 函数,它以非常简洁的方式将左值引用转换为右值引用。
示例 1
string str_1 = "123";
string s(std::move(str_1));/*str_1被转移构造到了s*/ //string(&&)
//string s2(str_1);/*拷贝构造函数*/ //string(string&)
std::cout << s << endl;;/*123*/
cout << str_1 << endl;/*str_1已被转移 所以为空*/
示例 2
#include<iostream>
#include "vector"
#include "string"
#include "functional"
#include "windows.h"
using namespace std;
class _string
{
public:
char*_data;
void alloc()
{
_data = (char*)malloc(sizeof(char)* 100);
}
_string&operator=(const char*s)
{
cout << "call =const char*" << endl;
strcpy(_data, s);
return *this;
}
_string &operator=(const _string& s)
{
cout << "call = const string&" << endl;
strcpy(_data, s.c_str());
return *this;
}
_string &operator=(_string&&s)
{
cout << "call =string&&" << endl;
this->_data = s._data;
s._data = 0;
return *this;
}
_string(_string&&s)
{
cout << "call string string &&" << endl;
this->_data = s._data;
s._data = 0;
}
_string(_string&s)
{
alloc();
cout << "call string string &" << endl;
strcpy(_data, s.c_str());
}
_string(const char*s)
{
alloc();
cout << "call string const char*" << endl;
strcpy(_data, s);
}
_string(const _string&s)
{
alloc();
cout << "call string const string &" << endl;
strcpy(_data, s.c_str());
}
_string()
{
alloc();
cout << "call string" << endl;
strcpy(_data, "\0");
}
~_string()
{
if (_data)
{
cout << "call ~_stirng with free" << endl;
free(_data);
return;
}
cout << "call ~_stirng" << endl;
}
const char* c_str() const
{
return (const char*)_data;
}
};
_string func()
{
_string str = "65546465";
//return str;
return std::move(str);
}
int main()
{
//{
_string&& s = (func());
//}
system("pause");
return 0;
}