我发现-fno-elide-constructors关闭NRVO/RVO,但NRVO/RVO有其自身的发生条件,有时也不发生。需要知道NRVO/RVO是否发生以理解何时发生额外的复制构建。我对编译时特性特别感兴趣。如果有一些特定的#pragma GCC...(它会在自身之后立即激活诊断)或使用静态Assert机制的东西,那就太好了。
-fno-elide-constructors
#pragma GCC...
nhhxz33t1#
我不知道任何gcc特定的诊断消息或其他方法,可以很容易地解决你的任务。正如你所发现的,-fno-elide-constructors将禁用复制/移动省略,所以你可以肯定的是,(N)RVO至少不会在这种情况下发生。然而,快速查看this C++11 working draft第12.8节中的第31段指出:当满足某些条件时,允许实现省略类对象的复制/移动构造,即使对象的复制/移动构造函数和/或析构函数有副作用。在这种情况下,实现将省略的复制/移动操作的源和目标简单地视为引用同一对象的两种不同方式,并且该对象的销毁发生在两个对象在没有优化的情况下被销毁的较晚时间。这种复制/移动操作的省略,称为复制省略,在以下情况下是允许的(可以结合使用以消除多个副本):
*在具有类返回类型的函数中的return语句中,当表达式是非易失性自动对象的名称(函数或catch-clause参数除外),该对象具有与函数返回类型相同的cv-非限定类型,通过将自动对象直接构造到函数的返回值中,可以省略复制/移动操作
...
*当一个没有绑定到引用的临时类对象(12.2)将被复制/移动到具有相同cv-非限定类型的类对象时,复制/移动操作可以通过将临时对象直接构造到省略的复制/移动的目标中来省略。
...当复制/移动省略发生时,本地auto对象与临时(返回)对象相同,而临时(返回)对象又与“存储”对象(存储返回值的位置)相同。因此,本地auto对象与存储对象相同,这意味着指针比较将等于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不发生时,指针比较可能取决于未定义的行为,因为本地auto对象不存在。进行指针比较会增加复杂性,但具有独立于编译器的优点。
a7qyws3x2#
是否有任何警告,使我们能够知道是否NRVO/RVO进行或不,在GCC?gcc (trunk)(尚未发布v14)有-Wnrvo
gcc (trunk)
-Wnrvo
gcc (trunk)在https://godbolt.org/上可用
2条答案
按热度按时间nhhxz33t1#
我不知道任何gcc特定的诊断消息或其他方法,可以很容易地解决你的任务。正如你所发现的,
-fno-elide-constructors
将禁用复制/移动省略,所以你可以肯定的是,(N)RVO至少不会在这种情况下发生。然而,快速查看this C++11 working draft第12.8节中的第31段指出:
当满足某些条件时,允许实现省略类对象的复制/移动构造,即使对象的复制/移动构造函数和/或析构函数有副作用。在这种情况下,实现将省略的复制/移动操作的源和目标简单地视为引用同一对象的两种不同方式,并且该对象的销毁发生在两个对象在没有优化的情况下被销毁的较晚时间。这种复制/移动操作的省略,称为复制省略,在以下情况下是允许的(可以结合使用以消除多个副本):
*在具有类返回类型的函数中的return语句中,当表达式是非易失性自动对象的名称(函数或catch-clause参数除外),该对象具有与函数返回类型相同的cv-非限定类型,通过将自动对象直接构造到函数的返回值中,可以省略复制/移动操作
...
*当一个没有绑定到引用的临时类对象(12.2)将被复制/移动到具有相同cv-非限定类型的类对象时,复制/移动操作可以通过将临时对象直接构造到省略的复制/移动的目标中来省略。
...
当复制/移动省略发生时,本地auto对象与临时(返回)对象相同,而临时(返回)对象又与“存储”对象(存储返回值的位置)相同。因此,本地auto对象与存储对象相同,这意味着指针比较将等于true。一个简单的例子来证明这一点:
字符串
启用/禁用
-fno-elide-constructors
会按预期更改打印的消息。注意:在最严格的意义上,当(N)RVO不发生时,指针比较可能取决于未定义的行为,因为本地auto对象不存在。进行指针比较会增加复杂性,但具有独立于编译器的优点。
a7qyws3x2#
是否有任何警告,使我们能够知道是否NRVO/RVO进行或不,在GCC?
gcc (trunk)
(尚未发布v14)有-Wnrvo
gcc (trunk)
在https://godbolt.org/上可用