C++ 从右值引用限定成员函数按值或右值引用返回?
在第12项中,Scott Meyers编写了以下类,以说明重载引用限定符上的成员函数是多么有用:C++ 从右值引用限定成员函数按值或右值引用返回?,c++,c++11,move-semantics,rvalue-reference,ref-qualifier,C++,C++11,Move Semantics,Rvalue Reference,Ref Qualifier,在第12项中,Scott Meyers编写了以下类,以说明重载引用限定符上的成员函数是多么有用: 类小部件{ 公众: 使用DataType=std::vector; … 用于左值小部件的DataType&data()&// {返回值;}//返回左值 用于右值小部件的数据类型data()&&// {return std::move(values);}//return rvalue … 私人: 数据类型值; }; 这似乎很清楚:现在non_temp_obj.data()将调用第一个重载并返回一个引
类小部件{
公众:
使用DataType=std::vector;
…
用于左值小部件的DataType&data()&//
{返回值;}//返回左值
用于右值小部件的数据类型data()&&//
{return std::move(values);}//return rvalue
…
私人:
数据类型值;
};
这似乎很清楚:现在non_temp_obj.data()
将调用第一个重载并返回一个引用到一个对象的一个成员,而make_temp_obj()
这里是我的第一个问题:关于&&
重载,为什么返回std::move(值)
而不仅仅是返回值代码>,考虑到我们是按值返回的?
然而,梅耶斯在书中写道
让data
成员函数的右值引用重载返回右值的更好方法是让它返回右值引用。这将避免为返回值创建临时对象,并且它将与第84页顶部附近原始数据
接口的按引用返回一致
我认为这意味着要改变
DataType数据()&&
{返回标准::移动(值);}
到
DataType&&data()&&
{返回标准::移动(值);}
但我不明白其中的原因,尤其是考虑到这一点,我确信书的版本是正确的,勘误表是错误的
那么我的第二个问题是:谁是对的?值是一个对象成员和左值,因此如果直接返回值,它将被复制到返回值,而不是移动。&&
ref限定重载的要点是避免制作不必要的副本return std::move(values)
通过将values
强制转换为一个右值来实现这一点,以便将其从中移动而不是复制
关于你问题的第二部分:两者都有各自的优点和缺点。正如您链接的答案所指出的,从&&
重载按值返回避免了生存期问题,因为如果引用立即绑定到返回的对象,则会延长其生存期。另一方面,按值返回可能会意外地破坏值的值。例如:
DataType Widget::data() &&
{ return std::move(values); }
void func() {
Widget foo;
std::move(foo).data(); // Moves-constructs a temporary from
// foo::value, which is then immediately
// destroyed.
auto bar = foo.data(); // Oops, foo::value was already moved from
// above and its value is likely gone.
}
对于第一点,RVO不应该介入并避免复制和移动吗?不,RVO只适用于函数局部变量,而不适用于对象成员。类似地,函数局部变量在返回时会自动从中移动,即使RVO不适用,但这同样不适用于对象成员。不确定这是意外的原因std::move(foo)
明确表示可以从中移动对象,因此我希望在该表达式之后状态会发生更改,否则我不会std::move
。在我看来,按值返回的主要缺点是额外的移动构造函数(对于std::array
,这并不便宜),在您的示例中,通过数据类型&
返回将如何改变发生的情况?是不是std::move(foo.data()
将创建和销毁对foo::value
的引用,从而在定义bar
时保留后者的完整性?