【问题标题】:RVO vs std::unique_ptr<> cleanupRVO 与 std::unique_ptr<> 清理
【发布时间】:2012-11-26 08:28:34
【问题描述】:

这是一个关于对象销毁与返回值优化的 C++ 规范的问题。

我可以期望 RVO 在 std::unique_ptr&lt;&gt; 清理之前返回正确的值吗?

Foo
Bar()
{
  std::unique_ptr<Foo> ptr = new Foo;
  return *ptr;
}

【问题讨论】:

    标签: c++ c++11 return-value-optimization object-destruction


    【解决方案1】:

    无论有没有 RVO,它都会返回正确的值(在这种情况下没有 RVO)。该函数返回一个具体的Foo,因此*ptr将在指针销毁之前复制到返回值中。

    也就是说,

    Foo foo;
    foo = Bar();
    

    类似于(将 unique_ptr 展开更明确)

      Foo foo;
      Foo* ptr = new Foo;
      foo = *ptr;
    finally:
      delete ptr;
    

    【讨论】:

      【解决方案2】:

      当函数返回类类型对象时,RVO 只在两种情况下被允许:

      • 返回的表达式是非易失性自动对象的名称,或者
      • 返回的表达式引用了一个尚未绑定到引用的临时对象。

      所以您的代码不会触发 RVO。

      如果Foo对象声明为自动存储,则允许编译器进行RVO:

      Foo bar()
      {
          Foo foo;
          return foo;    // foo can be constructed directly as the returned object
      }
      

      如果由于某种原因您必须使用new 创建对象并想消除复制操作,您可以使用std::move,它将表达式更改为右值:

      Foo bar()
      {
          std::unique_ptr<Foo> ptr(new Foo);
          return std::move(*ptr);    // No deep copy if Foo implements
                                     // its own move constructor
      }
      

      【讨论】:

      • @kfmfe04 我认为std::move() 在这种情况下不是一个好主意。根据Move Semantics and Compiler Optimizations 的说法,这让事情变得更糟。
      • 如果您正在寻找优化,(N)RVO 比移动构造函数最佳。对构造函数的移动操作仍然是浅拷贝——它比深拷贝好,但比没有拷贝更糟糕。
      • @MarkLakata 你是对的。 std::move 不应用于返回命名的自动对象。我已经编辑了我的答案。
      猜你喜欢
      • 1970-01-01
      • 2014-08-29
      • 2014-04-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-03-27
      • 2020-04-17
      相关资源
      最近更新 更多