在C ++ 11中返回右值引用或临时对象

时间:2019-01-26 13:48:48

标签: c++ rvalue-reference

有效的现代C ++ 项目12 中,有一个有关 C ++ 11函数的引用限定符的示例代码:

class Widget {
public:
    using DataType = std::vector<double>;
    ...
    DataType &data() &            // for lvalue Widgets
    { return values; }            // return lvalue

    DataType data() &&            // return rvalue Widgets
    { return std::move(values); } // return rvalue
    ...
private:
    DataType values;
};

那么为什么第二个data() 右值引用重载函数返回临时对象 DataType但不返回右值参考 DataType&&

2 个答案:

答案 0 :(得分:0)

我看到的唯一原因是当对象是prvalue的结果时避免创建悬空引用:

Widget foo();

auto&& x = foo().data();

如果foo().data()返回了对variable成员的右值引用,则x将是一个悬空引用,因为foo()的结果对象在初始化结束时被破坏了的x(完整表达式的结尾)。

另一方面,data()&&按值返回,x绑定到一个临时实现,该实现将与x相同。因此避免了悬挂参考。

data() &&的此返回类型在C ++中不是惯用的。通常,访问器函数返回一个引用,而上述用例可能会引发任何代码审阅者的“悬挂引用警报”。

这个data()&&的定义很聪明,但是却违反了常规。

答案 1 :(得分:0)

方法后的 &&& 有特殊用途:它们用作 ref value qualifier

从某种意义上说,您可以放在函数的参数声明之后(即在参数的 ) 之后)的所有内容意味着“仅当 *this 具有这些特性时才使用此方法”。< /p>

此处最典型的用法是 const 限定:仅在 const 上下文中调用覆盖:

class Widget {
void foo() {
cout << "Calling mutable foo\n";
}

void foo() const {
cout << "Calling const foo\n";
}
};

同样的事情可以用 &&& 来完成,告诉编译器在 *this 有匹配的限定符时选择这些覆盖。

但是你为什么要这样做?

当您想区分以下之一时,这很有用:

  • 在正常左值情况下给出对一些内部数据的引用
  • *this 是右值引用的情况下复制数据并且不会超过调用代码的引用

一个让很多人厌烦的常见例子是在 for 循环中的使用。

考虑以下代码(基于您的 Widget 示例):

Widget buildWidget() { return Widget(); }

int main() {
   for (auto i : buildWidget().data()) {
      cout << i << '\n';
   }
   return 0;
}

在这种情况下,将调用 && 覆盖,因为 Widget 返回的 buildWidget 对象没有名称,并且这是一个右值引用。

具体而言,一旦调用 data() 完成,底层的 Widget 对象(此处未命名)将立即死亡(它的生命周期将结束)。如果此 && 覆盖不存在,则对其 data 成员的左值引用将指向已破坏的对象。 这将是未定义的行为

一般来说,这个rvalue ref 限定的东西并不常见。只有在遇到这样的情况时才真正需要使用它(通常是当您想通过复制返回一个值时,*this 可能在调用后被破坏)。