【问题标题】:How can I be sure a routine is taking advantage of (N)RVO?我如何确定例行程序正在利用 (N)RVO?
【发布时间】:2012-03-08 17:05:10
【问题描述】:

我想确保我的日常活动尽可能利用 (N)RVO。除了通过生成的反汇编进行解析之外,我还能做些什么或检查一个例程是否正在使用 (N)RVO 编译?在这一点上,我最感兴趣的是 MSVC 和 GCC。

【问题讨论】:

  • 这并不能回答问题,但是如果编译器没有出现在您的应用程序分析数据中,它是否重要

标签: c++ visual-c++ optimization gcc return-value-optimization


【解决方案1】:

不,不是。

但是,您可以在编写代码时遵循指南。


未命名返回值优化

这几乎是每次您返回一个临时文件时都会触发的,即使在调试模式下也是如此。

return MyObject(....);

命名返回值优化

每次函数总是返回相同的局部变量时,这几乎都会触发:

MyObject func() {
  MyObject result;
  if (...) { return result; }

  result.push(0);
  return result;
}

您可以混合使用这些,但在这种情况下编译器几乎不可能应用 RVO:

MyObject func() {
  MyObject result;
  if (...) { return MyObject(...); }

  return result;
}

在这里,一个回报可能会受益于 RVO,而另一个则不会。我敢打赌第一个会被优化,因为如果你在返回槽中推测性地创建result 并且突然需要采用if 分支,你会被卡住。请注意,只需重新排序语句即可:

MyObject func() {
  if (...) { return MyObject(...); }

  MyObject result;

  return result;
}

因此,NRVO 的经验法则是,在 result 的声明和返回 result 本身以外的任何其他内容的 return result; 语句之间不应有 return 语句。


如果您遵循这一点,您的赔率就会对您有利。然后这只是代码审查的问题。

而且您还可以使您的代码更易于阅读,因为您不会在知道真正需要变量之前就声明它们!

【讨论】:

  • @DrewDormann 确实,已修复。
【解决方案2】:

您可以在析构函数中添加调试方法:

struct A
{
   ~A() { cout << "destructor called"; }
};

A foo()
{
   A a;
   return a;
}

如果调用了析构函数,则可能没有应用 RVO。

【讨论】:

    【解决方案3】:

    我能想到的可能方法是:

    1. 在你的类中实现一个引用计数机制来跟踪通过类创建的实例的数量,这很像 shared_ptr 所做的,这样你可以检测到你的类的额外副本被创建并如果没有发生复制省略,则删除。

    2. 您可以简单地将调试跟踪放在类的复制构造函数和析构函数中,如果没有发生复制省略,您会看到很多连续的复制构造函数和析构函数调试跟踪。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-03-20
      • 1970-01-01
      • 2010-09-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多