GCC NRVO/RVO警告

22

GCC中,有没有任何警告可以使我们知道是否执行了NRVO/RVO

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

我特别关注编译时特性。如果有一些特定的#pragma GCC...(激活紧随其后的诊断)或使用静态断言机制的东西,那就太好了。


1
据我所知,编译器通常不会告诉你这种优化的情况,尤其是它们何时、为什么发生或未发生,但有一些指南。https://dev59.com/EWw05IYBdhLWcg3wTwKY - user2485710
考虑到存在像-Winline这样的警告,这是很奇怪的。 - Tomilov Anatoliy
“-Wdisabled-optimization” 没有给出任何信息?那么您仍然可以查看 “-fdump-ipa-all” 的输出是否有所提示。 - Damon
@Damon,如何检查-Wdisabled-optimization是否可行?我无法使用-fdump-tree-nrv获得任何.nrv输出文件,并且似乎不存在-fopt-info-nrv-missed/-fopt-info-missed-nrv - Tomilov Anatoliy
对我来说可以,它将.nrv文件放在.o文件旁边——更大的挑战是阅读这个混乱的文件,因为它们不是非常人性化的文件。我自己只用过-Wdisabled-optimization一两次,因为噪音太烦人了,而回报很少。尽管当时它似乎工作得很好(对于它所做的事情)。 - Damon
tree-nrv 用于基本的、晚期的、与语言无关的优化,而不是 C++ 中较早出现在前端的强 N?RVO。在 GCC 的 bugzilla 上提交 RFE 是有道理的。 - Marc Glisse
2个回答

6
我不知道有任何gcc特定的诊断信息或其他可以轻松解决您任务的方法。正如您已经发现的那样,-fno-elide-constructors将禁用复制/移动省略,因此您可以确定在该情况下(N)RVO将不会发生。
然而,快速查看这个C++11工作草案第12.8节第31段表明:
当满足某些条件时,即使对象的复制/移动构造函数和/或析构函数具有副作用,实现也可以省略类对象的复制/移动构造,例如,在这种情况下,实现将源和目标视为引用同一对象的两种不同方式,并且该对象的销毁发生在没有进行优化时两个对象中较晚的时间点。这种复制/移动操作的省略,称为复制省略,可以在以下情况下使用(可以组合以消除多个复制):
- 在具有类返回类型的函数中的返回语句中,当表达式是非易失性自动对象的名称(除函数或catch子句参数之外),其cv限定类型与函数返回类型相同时,通过直接构造自动对象到函数的返回值中,可以省略复制/移动操作。 - 当未绑定到引用的临时类对象将被复制/移动到具有相同cv限定类型的类对象时,可以通过直接构造临时对象到省略复制/移动的目标中来省略复制/移动操作。
当发生复制/移动省略时,局部自动对象与临时(返回)对象相同,反过来,临时对象与“存储”对象(存储返回值的位置)相同。因此,局部自动对象与存储对象相同,这意味着指针比较将返回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未发生时,指针比较可能取决于未定义的行为,因为本地自动对象不存在。

进行指针比较会增加冗余代码,但具有与编译器无关的优点。


获取局部变量的地址有时会阻止优化,你同意吗? - OwnageIsMagic

2
在GCC中有没有任何警告可以让我们知道是否执行了NRVO/RVO?
gcc(trunk)(尚未发布的v14版本)具有-Wnrvo选项。
“如果编译器在允许的情况下(根据[class.copy.elision])未消除从局部变量到函数返回值的复制,则发出警告。这种消除通常被称为命名返回值优化。”
可以在https://godbolt.org/上获取gcc(trunk)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接