我想确保我的日常生活尽可能利用 (N)RVO。除了解析生成的反汇编结果之外,我还能做些什么或检查是否正在使用 (N)RVO 编译例程?目前我最感兴趣的是 MSVC 和 GCC。

有帮助吗?

解决方案

不,不是真的。

但是,您在编写代码时可以遵循准则。


未命名返回值优化

每次返回临时值时,这几乎都会被触发,即使在调试模式下也是如此。

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 的经验法则是不应该有 return 声明之间的声明 resultreturn result; 返回除以下内容之外的任何内容的语句 result 本身。


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

而且您还可以使代码更易于阅读,因为您在知道确实需要变量之前不会声明变量!

其他提示

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

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

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

如果调用析构函数,则可能未应用RVO。

我能想到的可能的方法有:

  1. 在类中实现引用计数机制,该机制跟踪通过类创建的实例的数量,这非常类似于 shared_ptr 这样,如果没有发生复制省略,您可以检测到正在创建和删除的类的额外副本。

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

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top