【问题标题】:Eliminating unnecessary copies when building composite objects在构建复合对象时消除不必要的副本
【发布时间】:2011-05-02 05:53:08
【问题描述】:

我正在考虑开发一些命名参数代码,但它让我想到了一些类似以下的代码:

#include <utility>

int main() 
{
  using std::make_pair;
  auto x = make_pair(1, make_pair(2, make_pair(3, make_pair(4,5))));
}

现在,一个简单的实现会首先执行“make_pair(4,5)”,然后将结果复制到“make_pair(3, ...)”的第二个元素中,然后将其复制到第二个元素中“make_pair(2, ...)”等

不幸的是,这将导致 O(n^2) 性能,并带有很多不必要的副本。我也看不出(命名的)返回值优化在这里有什么帮助。

理想情况下,make_pair(4,5)意识到它将在x的最后一个位置,并在那个位置构建自己。

更进一步:

#include <utility>

int main() 
{
  using std::make_pair;
  auto&& x1 = make_pair(3, make_pair(4,5));
  auto x2 = make_pair(1, make_pair(2, std::move(x1)));
}

我也想避免在这样的代码中复制。

这种优化是否如此明显以至于我应该假设编译器会执行它,或者我应该以其他方式对其进行编码以避免复制?

【问题讨论】:

  • 即使使用当前的 C++ 和体面的编译器,代码也不会产生任何不必要的副本(我用 g++ 编写了一个小测试,生成的汇编代码中没有副本)。
  • 像这样的陈述:我看不出(命名的)返回值优化在这里有什么帮助会让你大吃一惊。程序员真的不善于理解编译器的实际作用。试一试,看看实际发生了什么。然后你可以做出如下语句:编译器无法发现优化 X 如何让我的代码对编译器更友好

标签: c++ optimization rvalue-reference c++11


【解决方案1】:

[N]RVO 在这种情况下确实有帮助。基本上发生的情况是分配了一个复合对象,并且每个函数的“返回值”最终直接进入将保存结果的对象。

如果您打算做很多这样的事情(尤其是在 C++11 中),几乎可以肯定,使用元组会更清洁、更简单、更直接,所以您的:

auto x = make_pair(1, make_pair(2, make_pair(3, make_pair(4,5))));

最终会是这样的:

auto x = make_tuple(1, 2, 3, 4, 5);

这可能不会对生成的代码产生太大影响,但(至少在 IMO)它更容易阅读。

【讨论】:

    【解决方案2】:
    make_pair(1, make_pair(2, make_pair(3, make_pair(4,5))));
    

    作为另一个 make_pair 的参数的所有 make_pairs 将创建一个临时值,该临时值被视为右值引用,因此不会被复制。

    我想你真正想要的是make_tuple

    【讨论】:

      猜你喜欢
      • 2014-06-30
      • 1970-01-01
      • 2016-11-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-09-28
      相关资源
      最近更新 更多