1、为啥使用引用?
// An highlighted block
void function(string str)
{
... ...
}
看上面这段代码,如果不采用引用的方法,那么在函数被调用的时候,编译器会有一个参数赋值的过程,这就导致了内存和效率的浪费。
// An highlighted block
void main()
{
string ch = "abc";
function(ch);
}
编译器暗中会执行string str = ch这句,导致效率和内存的浪费,为了解决这个问题C++11采用了引用的方法,减少内存的浪费。
2、有了左值引用,为啥要加入右值引用
// An highlighted block
void function(string& str)
{
... ...
}
比如上面这个函数成功的解决了内存浪费的问题。但是有个新的问题,这个函数没法传入一个右值。什么是左值和右值?见收藏里的《一文读懂C++右值引用和std::move》,能取&的就是左值,不能的就是右值。
// An highlighted block
void main()
{
function("abc");//编译不过
}
因为"abc"是一个右值,左值引用只能接受左值,所以报错。但是在日常使用中,我们非常希望能直接进行以上的编码。左值引用要能接受右值,只需要加const就行了。
// An highlighted block
void function(const string& str)
{
... ...
}
但这又会出现一个新的问题,没法修改str的值,如果function需要对str进行修改,就出错了。为了解决这个问题C++11引入了右值引用。
3、右值引用
为了解决上面提到的问题function的代码调整为以下代码
// An highlighted block
void function(string&& str)
{
... ...
}
右值引用只能接受右值,不能接受左值。
// An highlighted block
void main()
{
string ch = "abc";
function(ch);//编译不过
}
但是我们希望同时能传入一个左值过去,怎么办?这就引出了移动函数move(),这个函数的功能是传入一个左值,返回一个右值,即右值引用接受左值的方法。
// An highlighted block
void main()
{
string ch = "abc";
function(move(ch));//编译通过
}
4、移动构造
上面的代码中编译器暗中会执行string str = move(ch)这句,但是这一句会触发string的移动构造函数
// An highlighted block
class string
{
public:
char* str;
... ...
string(string && s) : str(s.str)
{
s.str = new char[1];
s.str[0] = 0;
}
... ...
};
可以看到移动构造函数把参数s的内存清理了,值却给了自己。