21

GCC中是否有任何警告可以让我们知道NRVO/RVO是否执行?

我发现-fno-elide-constructors关闭NRVO/RVO,但是NRVO/RVO有它自己的条件发生,有时不会发生。当额外的复制构造发生时,需要知道NRVO/RVO是否发生理解。

我对编译时特性特别感兴趣。如果有一些特定#pragma GCC...的(它会在其自身之后立即激活诊断)或使用静态断言机制的东西,那就太好了。

4

1 回答 1

6

我不知道任何 gcc 特定的诊断消息或其他可以轻松解决您的任务的方法。正如您所发现的,-fno-elide-constructors将禁用复制/移动省略,因此您将确定至少在这种情况下不会发生 (N)RVO。

但是,快速浏览此 C++11 工作草案第 12.8 节中的第 31 段指出:

当满足某些条件时,允许实现省略类对象的复制/移动构造,即使对象的复制/移动构造函数和/或析构函数具有副作用。在这种情况下,实现将省略的复制/移动操作的源和目标简单地视为引用同一对象的两种不同方式,并且该对象的销毁发生在两个对象本应被删除的较晚时间。没有优化就被破坏了。这种复制/移动操作的省略,称为复制省略,在以下情况下是允许的(可以结合起来消除多个副本):

  • 在具有类返回类型的函数的 return 语句中,当表达式是具有与函数返回类型相同的 cv 非限定类型的非易失性自动对象(函数或 catch 子句参数除外)的名称时,通过将自动对象直接构造到函数的返回值中,可以省略复制/移动操作

...

  • 当尚未绑定到引用(12.2) 的临时类对象将被复制/移动到具有相同 cv-unqualified 类型的类对象时,可以通过将临时对象直接构造到目标中来省略复制/移动操作省略的复制/移动

...

当复制/移动省略发生时,本地自动对象与临时(返回)对象相同,而临时(返回)对象又与“存储”对象(存储返回值的位置)相同。因此本地自动对象与存储对象相同,这意味着指针比较将等于 true。一个简单的例子来证明这一点:

#include <iostream>
#include <vector>

std::vector<int> testNRVO(int value, size_t size, const std::vector<int> **localVec)
{
   std::vector<int> vec(size, value);

   *localVec = &vec;

   /* Do something here.. */

   return vec;
}

int main()
{
   const std::vector<int> *localVec = nullptr;

   std::vector<int> vec = testNRVO(0, 10, &localVec);

   if (&vec == localVec)
      std::cout << "NRVO was applied" << std::endl;
   else
      std::cout << "NRVO was not applied" << std::endl;
}

启用/禁用-fno-elide-constructors会按预期更改打印的消息。注意:在最严格的意义上,指针比较可能取决于未发生 (N)RVO 时的未定义行为,因为本地自动对象不存在。

进行指针比较会增加麻烦,但具有编译器独立性的优势。

于 2014-01-20T18:26:44.953 回答