It declares an rvalue reference (standards proposal doc).
(它声明一个右值参考 (标准建议文档)。)
Here's an introduction to rvalue references .
(这是右值引用的简介 。)
Here's a fantastic in-depth look at rvalue references by one of Microsoft's standard library developers .
(这是Microsoft标准库开发人员之一对rvalue引用进行的精彩深入研究。)
CAUTION: the linked article on MSDN ("Rvalue References: C++0x Features in VC10, Part 2") is a very clear introduction to Rvalue references, but makes statements about Rvalue references that were once true in the draft C++11 standard, but are not true for the final one!
(注意: MSDN上的链接文章(“ Rvalue参考:VC10中的C ++ 0x功能,第2部分”)是对Rvalue引用的非常清晰的介绍,但是对有关Rvalue引用的声明在C ++ 11草案中曾经是正确的。标准,但对于最后一个不是正确的!)
Specifically, it says at various points that rvalue references can bind to lvalues, which was once true, but was changed.(eg int x; int &&rrx = x; no longer compiles in GCC) – drewbarbs Jul 13 '14 at 16:12 (具体来说,它说在各个点上右值引用可以绑定到左值,这曾经是真实的,但是已经被更改。(例如int x; int && rrx = x;不再在GCC中编译)– drewbarbs 2014年7月13日在16:12)
The biggest difference between a C++03 reference (now called an lvalue reference in C++11) is that it can bind to an rvalue like a temporary without having to be const.
(C ++ 03引用(在C ++ 11中现在称为左值引用)之间的最大区别在于,它可以像临时元素一样绑定到右值,而不必使用const。)
Thus, this syntax is now legal: (因此,此语法现在合法:)
T&& r = T();
rvalue references primarily provide for the following:
(右值引用主要提供以下内容:)
Move semantics .
(移动语义 。)
A move constructor and move assignment operator can now be defined that takes an rvalue reference instead of the usual const-lvalue reference. (现在可以定义移动构造函数和移动赋值运算符,该运算符采用右值引用而不是通常的const-左值引用。)
A move functions like a copy, except it is not obliged to keep the source unchanged; (移动的功能类似于副本,只是它没有义务保持源不变。)
in fact, it usually modifies the source such that it no longer owns the moved resources. (实际上,它通常会修改源,使其不再拥有已移动的资源。)
This is great for eliminating extraneous copies, especially in standard library implementations. (这对于消除无关的副本非常有用,尤其是在标准库实现中。)
For example, a copy constructor might look like this:
(例如,复制构造函数可能如下所示:)
foo(foo const& other)
{
this->length = other.length;
this->ptr = new int[other.length];
copy(other.ptr, other.ptr + other.length, this->ptr);
}
If this constructor was passed a temporary, the copy would be unnecessary because we know the temporary will just be destroyed;
(如果将此构造函数传递给临时对象,则不需要复制,因为我们知道临时对象将被销毁。)
why not make use of the resources the temporary already allocated? (为什么不利用已分配的临时资源?)
In C++03, there's no way to prevent the copy as we cannot determine we were passed a temporary. (在C ++ 03中,由于无法确定我们是否被临时传递,因此无法阻止复制。)
In C++11, we can overload a move constructor: (在C ++ 11中,我们可以重载move构造函数:)
foo(foo&& other)
{
this->length = other.length;
this->ptr = other.ptr;
other.length = 0;
other.ptr = nullptr;
}
Notice the big difference here: the move constructor actually modifies its argument.
(注意这里的最大区别:move构造函数实际上是修改其参数。)
This would effectively "move" the temporary into the object being constructed, thereby eliminating the unnecessary copy. (这将有效地将临时文件“移动”到正在构造的对象中,从而消除了不必要的复制。)
The move constructor would be used for temporaries and for non-const lvalue references that are explicitly converted to rvalue references using the std::move
function (it just performs the conversion).
(move构造函数将用于临时对象和非常量左值引用,这些引用使用std::move
函数(仅执行转换)显式转换为右值引用。)
The following code both invoke the move constructor for f1
and f2
: (以下代码均调用f1
和f2
的move构造函数:)
foo f1((foo())); // Move a temporary into f1; temporary becomes "empty"
foo f2 = std::move(f1); // Move f1 into f2; f1 is now "empty"
Perfect forwarding .
(完美的转发 。)
rvalue references allow us to properly forward arguments for templated functions. (右值引用使我们能够正确转发模板函数的参数。)
Take for example this factory function: (以这个工厂功能为例:)
template <typename T, typename A1>
std::unique_ptr<T> factory(A1& a1)
{
return std::unique_ptr<T>(new T(a1));
}
If we called factory<foo>(5)
, the argument will be deduced to be int&
, which will not bind to a literal 5, even if foo
's constructor takes an int
.
(如果我们调用factory<foo>(5)
,则将推导该参数为int&
,即使foo
的构造函数采用int
,该参数也不会绑定到文字5。)
Well, we could instead use A1 const&
, but what if foo
takes the constructor argument by non-const reference? (好吧,我们可以改用A1 const&
,但是如果foo
通过非const引用接受构造函数参数怎么办?)
To make a truly generic factory function, we would have to overload factory on A1&
and on A1 const&
. (为了实现真正的通用工厂功能,我们必须在A1&
和A1 const&
上重载工厂。)
That might be fine if factory takes 1 parameter type, but each additional parameter type would multiply the necessary overload set by 2. That's very quickly unmaintainable. (如果factory采用1个参数类型,可能会很好,但是每个其他参数类型都会将必需的重载设置乘以2。这很快就无法维护。)
rvalue references fix this problem by allowing the standard library to define a std::forward
function that can properly forward lvalue/rvalue references.
(右值引用通过允许标准库定义可以正确转发左值/右值引用的std::forward
函数来解决此问题。)
For more information about how std::forward
works, see this excellent answer . (有关std::forward
工作方式的更多信息,请参见此出色的答案 。)
This enables us to define the factory function like this:
(这使我们能够定义工厂功能,如下所示:)
template <typename T, typename A1>
std::unique_ptr<T> factory(A1&& a1)
{
return std::unique_ptr<T>(new T(std::forward<A1>(a1)));
}
Now the argument's rvalue/lvalue-ness is preserved when passed to T
's constructor.
(现在,当传递给T
的构造函数时,参数的rvalue / lvalue-ness得以保留。)
That means that if factory is called with an rvalue, T
's constructor is called with an rvalue. (这意味着,如果使用rvalue调用factory,则使用rvalue调用T
的构造函数。)
If factory is called with an lvalue, T
's constructor is called with an lvalue. (如果使用左值调用factory,则使用左值调用T
的构造函数。)
The improved factory function works because of one special rule: (改进的工厂功能之所以有效,是因为以下一条特殊规则:)
When the function parameter type is of the form T&&
where T
is a template parameter, and the function argument is an lvalue of type A
, the type A&
is used for template argument deduction.
(当函数参数类型的形式为T&&
,其中T
是模板参数,并且函数参数是类型A
的左值时,类型A&
用于模板参数推导。)
Thus, we can use factory like so:
(因此,我们可以像这样使用工厂:)
auto p1 = factory<foo>(foo()); // calls foo(foo&&)
auto p2 = factory<foo>(*p1); // calls foo(foo const&)
Important rvalue reference properties :
(重要的右值参考属性 :)
- For overload resolution, lvalues prefer binding to lvalue references and rvalues prefer binding to rvalue references .
(对于重载解析, 左值倾向于绑定到左值引用,而右值倾向于绑定到右值引用 。)
Hence why temporaries prefer invoking a move constructor / move assignment operator over a copy constructor / assignment operator. (因此,为什么临时人员比复制构造函数/赋值运算符更喜欢调用移动构造函数/移动赋值运算符。)
- rvalue references will implicitly bind to rvalues and to temporaries that are the result of an implicit conversion .
(右值引用将隐式绑定到右值和作为隐式转换结果的临时对象 。)
ie float f = 0f; int&& i = f;
(即float f = 0f; int&& i = f;
) float f = 0f; int&& i = f;
is well formed because float is implicitly convertible to int;
(格式良好,因为float可以隐式转换为int;)
the reference would be to a temporary that is the result of the conversion. (该引用将是转换后的临时结果。)
- Named rvalue references are lvalues.
(命名的右值引用是左值。)
Unnamed rvalue references are rvalues. (未命名的右值引用是右值。)
This is important to understand why the std::move
call is necessary in: foo&& r = foo(); foo f = std::move(r);
(了解为什么为什么必须在以下位置进行std::move
调用非常重要: foo&& r = foo(); foo f = std::move(r);
) foo&& r = foo(); foo f = std::move(r);