C++ 从右值引用限定成员函数按值或右值引用返回?

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()将调用第一个重载并返回一个引

在第12项中,Scott Meyers编写了以下类,以说明重载引用限定符上的成员函数是多么有用:

类小部件{
公众:
使用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
时保留后者的完整性?