【问题标题】:Return rvalue reference or temporary object in C++11 [duplicate]在C ++ 11中返回右值引用或临时对象[重复]
【发布时间】:2021-02-27 14:50:05
【问题描述】:

在Effective Modern C++ item 12中,有一个关于C++11函数的引用限定符的示例代码:

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

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

那么为什么第二个data() 右值引用重载函数返回一个临时对象 DataType而不是一个右值引用 @987654324 @?

【问题讨论】:

    标签: c++ rvalue-reference


    【解决方案1】:

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

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

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

    另一方面,data()&amp;&amp; 按值返回,x 绑定到与x 具有相同生命周期的临时实现。所以避免了悬空引用。

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

    data()&amp;&amp; 的这个定义很聪明,但它打破了常规。

    【讨论】:

      【解决方案2】:

      方法后面的&amp; 或&amp;&amp; 有一个特殊用途:它们用作ref value qualifier。

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

      这里最常见的用法是const 限定:仅在 const 上下文中调用覆盖:

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

      &amp;&amp; 或 &amp; 可以做同样的事情,告诉编译器在 *this 具有匹配的限定符时选择这些覆盖。

      但是你为什么要这样做呢?

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

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

      一个让很多人印象深刻的常见例子是在 for 循环中的使用。

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

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

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

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-02-14
        • 1970-01-01
        • 1970-01-01
        • 2011-02-14
        • 1970-01-01
        • 2012-07-18
        相关资源
        最近更新 更多