我一直在研究C++ 11的一些新功能,而我注意到的一个是在声明变量(如T&& var
)时使用双“&”号。
首先,这只野兽叫什么?我希望Google允许我们搜索这样的标点符号。
这到底是什么意思?
乍一看,它似乎是一个双引用(例如C风格的双指针T** var
),但是我很难考虑到该用例。
最佳答案
它声明了rvalue reference(标准提案文档)。
这是rvalue references的介绍。
这是对Microsoft标准库developers之一的右值引用的精彩深入研究。
C++ 03引用(在C++ 11中现在称为左值引用)之间的最大区别在于,它可以像临时对象一样绑定(bind)到右值,而不必使用const。因此,此语法现在合法:
T&& r = T();
右值引用主要提供以下内容:
移动语义。现在可以定义移动构造函数和移动赋值运算符,该运算符采用右值引用而不是通常的const-左值引用。移动的功能类似于副本,只是它没有义务保持源不变。实际上,它通常会修改源,使其不再拥有移动的资源。这对于消除多余的副本非常有用,尤其是在标准库实现中。
例如,复制构造函数可能如下所示:
foo(foo const& other)
{
this->length = other.length;
this->ptr = new int[other.length];
copy(other.ptr, other.ptr + other.length, this->ptr);
}
如果将此构造函数传递给临时对象,则不需要复制,因为我们知道临时对象将被销毁。为什么不利用已分配的临时资源?在C++ 03中,由于无法确定我们是否被临时传递,因此无法阻止复制。在C++ 11中,我们可以重载move构造函数:
foo(foo&& other)
{
this->length = other.length;
this->ptr = other.ptr;
other.length = 0;
other.ptr = nullptr;
}
注意这里的最大区别:move构造函数实际上是修改其参数。这将有效地将临时文件“移动”到正在构造的对象中,从而消除了不必要的复制。
move构造函数将用于临时文件和使用
std::move
函数(仅执行转换)显式转换为右值引用的非常量左值引用。以下代码均调用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"
完美转发。右值引用使我们能够正确转发模板函数的参数。以这个工厂功能为例:
template <typename T, typename A1>
std::unique_ptr<T> factory(A1& a1)
{
return std::unique_ptr<T>(new T(a1));
}
如果我们调用
factory<foo>(5)
,则将推导该参数为int&
,即使foo
的构造函数采用int
,该参数也不会绑定(bind)到文字5。好吧,我们可以改用A1 const&
,但是如果foo
通过非const引用接受构造函数参数怎么办?为了实现真正的通用工厂功能,我们必须在A1&
和A1 const&
上重载工厂。如果factory采用1个参数类型,则可能会很好,但是每个其他参数类型都会将必需的重载设置乘以2。这很快就无法维护。右值引用通过允许标准库定义可以正确转发左值/右值引用的
std::forward
函数来解决此问题。有关std::forward
的工作方式的更多信息,请参见this excellent answer。这使我们能够定义工厂功能,如下所示:
template <typename T, typename A1>
std::unique_ptr<T> factory(A1&& a1)
{
return std::unique_ptr<T>(new T(std::forward<A1>(a1)));
}
现在,当传递给
T
的构造函数时,参数的rvalue / lvalue-ness得以保留。这意味着,如果使用rvalue调用factory,则使用rvalue调用T
的构造函数。如果使用左值调用factory,则使用左值调用T
的构造函数。改进的工厂功能之所以有效,是因为以下一条特殊规则:因此,我们可以像这样使用工厂:
auto p1 = factory<foo>(foo()); // calls foo(foo&&)
auto p2 = factory<foo>(*p1); // calls foo(foo const&)
重要的右值参考属性:
float f = 0f; int&& i = f;
格式正确,因为float可以隐式转换为int;该引用将是转换后的结果。 std::move
调用:foo&& r = foo(); foo f = std::move(r);
关于c++ - C++ 11中的T &&(双“&”号)是什么意思?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/64141464/