作者在 2011-12-05 23:26:08 发布以下内容
1、具名的右值引用将退化成左值
Rvalue&& r = Rvalue(); // r 是一个左值,虽然它被声明为右值引用。
// 在这样的情况下 r 如同一个局部对象:Rvalue r;
// 在这样的情况下 r 如同一个局部对象:Rvalue r;
void Fun(Rvalue&& _r) // _r 也是一个左值,你可以取它地址,但这是一个危险动作。
{
Rvalue t = _r; // 不会调用 Rvalue(Rvalue&&) 转移构造函数,而是调用
} // Rvalue(const Rvalue&) 复制构造函数。
2、不能把右值引用绑定到左值,但是强制转换可以打破这规定
Rvalue r;
Fun(r); // 这是错误的,左值不能被绑定到右值引用。
Fun((Rvalue&&)r); // 这样就可以了,r 是以引用方式传递。
Fun(std::move(r)); // 效果和强制转换一样,但这里 r 没有被转移,看下面转移语义。
Fun(r); // 这是错误的,左值不能被绑定到右值引用。
Fun((Rvalue&&)r); // 这样就可以了,r 是以引用方式传递。
Fun(std::move(r)); // 效果和强制转换一样,但这里 r 没有被转移,看下面转移语义。
3、转移语义
要实现转移语义,必须对类实现转移构造函数和转移赋值函数,如下类似:
Rvalue(Rvalue&&); // 这是一个转移构造函数。
Rvalue& operator = (Rvalue&&); // 这是一个转移赋值函数。
Rvalue(Rvalue&&); // 这是一个转移构造函数。
Rvalue& operator = (Rvalue&&); // 这是一个转移赋值函数。
有了上面这两样函数就可以这样使用:
Rvalue r1;
Rvalue r2 = std::move(r1); // 转移 r1 中的资源,r1 不可用了。
// 调用 Rvalue(Rvalue&&) 转移构造函数。
Rvalue r3;
r3 = std::move(r2); // 转移 r2 中的资源,r2 不可用了。
// 调用 Rvalue& operator = (Rvalue&&); 转移赋值函数。
Rvalue r1;
Rvalue r2 = std::move(r1); // 转移 r1 中的资源,r1 不可用了。
// 调用 Rvalue(Rvalue&&) 转移构造函数。
Rvalue r3;
r3 = std::move(r2); // 转移 r2 中的资源,r2 不可用了。
// 调用 Rvalue& operator = (Rvalue&&); 转移赋值函数。
回看上面的一段语句:
Fun(std::move(r)); // 在这里没有发生转移情况,因为 Fun 函数的参数是右值引用。
// 没有对象构成 Rvalue(Rvalue&&) 转移构造函数调用。
如果 Fun 是如下定义,那就会发生转移:
void Fun(Rvalue _r)
{
}
Fun(std::move(r)); // 在这里没有发生转移情况,因为 Fun 函数的参数是右值引用。
// 没有对象构成 Rvalue(Rvalue&&) 转移构造函数调用。
如果 Fun 是如下定义,那就会发生转移:
void Fun(Rvalue _r)
{
}
4、一些想法
函数如果使用右值引用作为形参,那么意味着实参是临时的变量或对象。可以取他们的地址,但是不能超过
函数范围的持有。这样意味这这个参数与函数中的局部变量或对象起了一样的作用,只是它引用自外部而
已。
对于转移语义,对类来说就是可以只进行浅拷贝而不需要深拷贝,这是可掌握的。以前的返回值诟病,现在
通过转移语义可以大大的化解效率问题。如果不能 RVO ,那么还是要多次调用构造函数和析构函数,但比
起以前复制语义,现在就高效多了。
起以前复制语义,现在就高效多了。
如果不深入模板中使用右值引用,那么新的“引用折叠”概念基本上用不到。
引用折叠规则:
X& & = X&
X&& & = X&
X& && = X&
X&& && = X&&
X& & = X&
X&& & = X&
X& && = X&
X&& && = X&&