菜鸟笔记
提升您的技术认知

右值引用-ag真人游戏

1. 什么是右值引用

右值引用是c 11新加的一种引用类型,是一种仅能绑定到右值上的引用。不同于左值引用仅用一个&表示,右值引用用两个&&表示。

int x{ 5 };
int& lref{ x }; // l-value refrence initialized with l-value x 
int&& rref{ 5 } // r-value refrence initialized with r-value 5

右值引用有两个非常有用的性质: 1. 右值引用将初始化他们的对象的寿命延长到右值引用的寿命;2. 非常量的右值引用允许修改右值。

看一个实际例子:

#include 
 
class fraction
{
private:
	int m_numerator;
	int m_denominator;
 
public:
	fraction(int numerator = 0, int denominator = 1) :
		m_numerator{ numerator }, m_denominator{ denominator }
	{
	}
 
	friend std::ostream& operator<<(std::ostream& out, const fraction &f1)
	{
		out << f1.m_numerator << '/' << f1.m_denominator;
		return out;
	}
};
 
int main()
{
	auto &&rref{ fraction{ 3, 5 } }; // r-value reference to temporary fraction
	
    // f1 of operator<< binds to the temporary, no copies are created.
    std::cout << rref << '\n';
 
	return 0;
} // rref (and the temporary fraction) goes out of scope here

这段代码打印出:

3/5

fraction{ 3, 5 }是一个匿名对象(临时对象),在这行语句结束的时候就出了作用域,本来应该被销毁掉,但是我们用了一个右值引用来绑定它,因此延长了它的生命期,直到main函数结束,局部变量rref被销毁的时候,这个临时对象才会被销毁。
再看另外一个例子:

#include
int main()
{
    int &&ref{ 5 };
    rref = 10;
    std::cout << rref << std::endl;
    return 0;
}

这段代码执行结果是:

10

这里用字面值初始化一个右值引用,会创建一个临时对象,我们可以通过右值引用来修改这个对象。

2. 右值引用作为函数参数

右值引用最有用的地方在于作为函数参数,尤其是在写重载函数时,希望对传入的左值和右值表现出不同的行为。

void fun(const int& lref)
{
    std::cout << "l-value reference to const." << std::endl;
}
void fun(int &&rref)
{
    std::cout << "r-value reference." << std::endl;   
}
int main()
{
    int x{ 5 };
    fun(x); // l-value argument calls l-value version of fun()
    fun(5); // r-value argument calls r-value version of fun()
    return 0;
}

这段代码打印出:

l-value reference to const.
r-value reference.

可以看出,当传入的参数是左值时,调用的是左值版本的fun(), 当传入的参数是右值时,调用的是右值版本的fun()。可是这有什么用呢?这对于移动语义来说是一个非常重要的特性,后面会继续讨论。
再看一个有意思的例子:

int &&ref{ 5 };
fun(ref);

ref是一个右值引用,那么fun(ref)调用的是右值引用版本吗?事实上,这里调用的是左值版本的fun()函数。虽然ref是一个右值引用,但是这仅说明它绑定的对象是一个右值,它本身是一个局部变量,是一个左值,因此这行代码调用的是左值版本的fun()。

3. 不要返回右值引用

在绝大多数情况下,你都不应该返回右值引用。因为右值引用绑定的对象在出作用域之后就会被销毁,因此从函数返回,你智能得到一个"hanging reference"。

网站地图