【问题标题】:Will RVO happen when returning std::pair?返回 std::pair 时会发生 RVO 吗?
【发布时间】:2012-12-12 04:33:34
【问题描述】:

一个函数需要返回两个值给调用者。最好的实施方式是什么?

选项 1:

pair<U,V> myfunc()
{
...
return make_pair(getU(),getV());
}

pair<U,V> mypair = myfunc();

选项 1.1:

// Same defn
U u; V v;
tie(u,v) = myfunc();

选项 2:

void myfunc(U& u , V& v)
{
u = getU(); v= getV();
}

U u; V v;
myfunc(u,v);

我知道 Option2 没有复制/移动,但它看起来很难看。选项 1、1.1 中是否会发生任何复制/移动?让我们假设 U 和 V 是支持复制/移动操作的巨大对象。

问:理论上是否可以按照标准进行任何 RVO/NRVO 优化?如果是,gcc 或任何其他编译器是否已实现?

【问题讨论】:

  • 我不知道任何关于std::pair 会抑制 RVO/NRVO 的信息。通过包含一个告诉您何时发生复制的复制构造函数,通常可以很容易地进行测试。
  • g++ 实现了防止复制对的 RVO,但是您仍然将 u 和 v 的副本复制到对中。
  • 我进行了一些测试,我发现使用 g++,哪个更快取决于可能的内联以及 U 和 V 的复制构造函数的复杂性。如果您只是在寻找性能,我认为您必须对其进行分析以确定哪个最快。
  • 这并不是您问题的真正答案,但我建议使用简单的结构而不是对。对是丑陋和沉重的重量。一旦我看到了类似 time.first 的代码;时间.秒;不可读。时间.分钟;时间.秒;好多了。

标签: c++ c++11 std-pair rvo nrvo


【解决方案1】:

返回std::pair时会发生RVO吗?

可以。

一定会发生吗?

不,不是。


C++11 标准:第 12.8/31 节:

当满足某些条件时,允许实现省略类对象的复制/移动构造,即使对象的复制/移动构造函数和/或析构函数有副作用。

复制省略不是保证功能。这是一种优化编译器可以尽可能地执行。没有什么特别的 w.r.t std::pair。如果编译器足以检测到优化机会,它就会这样做。所以你的问题是编译器特定的,但是同样的规则适用于std::pair 和任何其他类。

【讨论】:

    【解决方案2】:

    虽然不能保证 RVO,但在 C++11 中,您定义的函数我相信至少必须移动返回,所以我建议保留更清晰的定义而不是扭曲它以接受输出变量(除非您有使用它们的特定政策)。

    此外,即使此示例确实使用了 RVO,您对 make_pair 的显式使用意味着您将始终至少有一个额外的对构造,因此是一个移动操作。将其更改为返回大括号初始化的表达式:

    return { getU(), getV() };
    

    【讨论】:

      【解决方案3】:

      RVO 或复制省略依赖于编译器,所以如果你想拥有 RVO 并避免调用复制构造函数,最好的选择是使用指针。

      在我们的产品中,我们使用使用指针和提升容器指针来避免复制构造函数。这确实使性能提升了大约 10%。

      回答你的问题, 在选项 1 中,不会调用 U 和 V 的复制构造函数,因为您没有返回 U 或 V,而是返回 std::pair 对象,因此将调用它的复制构造函数,并且大多数编译器肯定会在此处使用 RVO 来避免这种情况。

      谢谢 尼拉吉拉蒂

      【讨论】:

        【解决方案4】:

        如果您需要在创建配对后对 uv 做额外的工作,我发现以下模式在 C++17 中非常灵活:

        pair<U,V> myfunc()
        {
          auto out = make_pair(getU(),getV());
          auto& [u, v] = out;
          // Work with u and v
          return out;
        }
        

        这应该是编译器使用命名返回值优化的一个非常简单的例子

        【讨论】:

          猜你喜欢
          • 2020-09-21
          • 2013-10-16
          • 1970-01-01
          • 2020-04-22
          • 1970-01-01
          • 2013-09-04
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多