C++ 什么是「;*此”的右值引用;对于
标准还为成员函数调用引用限定符的“this的右值引用”最典型的用例是什么C++ 什么是「;*此”的右值引用;对于,c++,c++11,rvalue-reference,C++,C++11,Rvalue Reference,标准还为成员函数调用引用限定符的“this的右值引用”最典型的用例是什么 顺便说一句,关于这个语言特性有一个很好的解释 调用时,每个成员函数都有一个隐式对象参数,*此引用该参数 所以(a)这些正常函数重载: void f(const T&); void f(T&&); struct C { void f() const &; void f() &&; }; 调用时,如f(x);和(b)这些成员函数重载: void f(const
顺便说一句,关于这个语言特性有一个很好的解释 调用时,每个成员函数都有一个隐式对象参数,
*此
引用该参数
所以(a)这些正常函数重载:
void f(const T&);
void f(T&&);
struct C
{
void f() const &;
void f() &&;
};
调用时,如f(x)
;和(b)这些成员函数重载:
void f(const T&);
void f(T&&);
struct C
{
void f() const &;
void f() &&;
};
当调用类似于x.f()
-时,(a)和(b)都具有相似的生存能力和排名
因此,用例本质上是相同的。它们支持移动语义优化。在rvalue成员函数中,您基本上可以掠夺对象资源,因为您知道它是一个即将过期的对象(即将被删除):
例如:
struct C
{
C operator+(const C& that) const &
{
C c(*this); // take a copy of this
c += that;
return c;
}
C operator+(const C& that) &&
{
(*this) += that;
return move(*this); // moving this is ok here
}
}
当对右值调用时,某些操作可能更有效,因此对
*的值类别进行重载可以自动使用最有效的实现,例如
struct Buffer
{
std::string m_data;
public:
std::string str() const& { return m_data; } // copies data
std::string str()&& { return std::move(m_data); } // moves data
};
(此优化可针对std::ostringstream
,但尚未正式提出。)
有些操作调用右值没有意义,因此在*上重载此可以删除右值表单:
int main()
{
C c;
c.f(); // lvalue, so calls lvalue-reference member f
C().f(); // temporary is prvalue, so called rvalue-reference member f
move(c).f(); // move changes c to xvalue, so again calls rvalue-reference member f
}
struct Foo
{
void mutate()&;
void mutate()&& = delete;
};
我还没有真正需要使用这个功能,但是现在我关心的两个编译器都支持它,也许我会发现它有更多的用途。在我的编译器框架中(不久将发布)™), 将令牌等信息项传递到编译器对象中,然后调用finalize
以指示流的结束
如果不调用finalize
,就销毁一个对象是不好的,因为它不会清除所有的输出。但是finalize
不能由析构函数完成,因为它会引发异常,同样,如果解析器已经中止,那么要求finalize
获得更多输出也是错误的
在所有输入都已被另一个对象封装的情况下,最好将输入传递给右值编译器对象
pile< lexer, parser >( output_handler ).pass( open_file( "source.q" ) );
这为添加另一个重载提供了空间,该重载可以正确地完成对象。它是右值引用限定的,因此只有在对即将过期的对象调用时才会选中它
void pass( input_file f ) && {
pass( std::move( f ) ); // dispatch to lvalue case
finalize();
}
现在用户几乎不需要担心调用finalize
,因为大多数编译器对象最终都被实例化为临时对象
注意,这类事情对于ref限定成员并不特殊。任何函数都可以对t&
和t&
单独重载。目前实际实现pass
的方式是使用完美的转发,然后回溯来确定正确的语义:
template< typename compiler, typename arg >
void pass( compiler && c, arg a ) {
c.take_input( a );
if ( ! std::is_reference< compiler >::value ) {
c.finalize();
}
}
template
无效传递(编译器(&c,参数a){
c、 获取输入(a);
如果(!std::is_reference::value){
c、 定稿();
}
}
重载有很多方法。实际上,非限定成员函数不关心类别(左值或右值)是不寻常的调用它们的对象,而不是将该信息传递到函数中。除了隐式this
之外的任何函数参数都必须说明其参数的类别。现在编译器支持它,我希望很快会看到一两篇关于该主题的文章弹出。gcc只是在4.8.1中实现了它,所以没有太多的p人们已经开始使用这个功能了。基本上,只要你想让用户不创建类的永久对象,而只使用临时对象,你就可以通过创建所需的成员函数&&
来实现这一点。对于你链接到的问题,示例和解释还不够吗?我看到弹出的一个常见示例是左值only>代码>运算符=< /代码>。类似于<代码> t和运算符=(t const &);将阻止<代码>()(t/);< />代码>编译。也考虑那些没有意义的成员调用rVals,如赋值运算符。@ DestMg:是的,rValor(PROVALUE或XVALUE)将不可绑定到<代码>空隙F(t&)。
,因此那里的用例与T::f()相同&
w.r.t.隐式对象参数。我的主要观点是注意正常函数参数和隐式对象参数之间的正交关系-因此,当值类别和重载选择应用于正常函数参数时,对它们的一般理解可以重新调整用途,就像隐式对象参数的成员函数一样object参数(只有细微的差异不值得一提)。FWIW,我甚至不想为移动而烦恼。只需添加到自身,然后再移动。@R.MartinhoFernandes:这取决于移动构造函数和操作符+=
实际做什么,但在某些情况下它可能更有效。已更改,谢谢。操作符不应该吗+(…)&&
返回C&&
以避免不必要的临时性?“对于未使用ref限定符声明的非静态成员函数,另一条规则适用:即使隐式对象参数不是const限定的,只要在所有其他方面参数可以转换为隐式对象参数的类型,右值也可以绑定到参数。”因此Foo::mutate()
没有ref限定符对右值是可行的……关于排名:“S1和S2是引用绑定(8.5.3),都不引用未声明ref限定符的非静态成员函数的隐式对象参数,S1将右值引用绑定到右值,S2绑定左值引用。“。因此,在mutate()no ref限定符
和mutate()&&
之间使用右值将是不明确的。这是您的意图吗?即我认为您最终得到了想要的效果,但诊断可能不理想(错误模糊重载)。不,这不是我的意图,我只是在一个