我希望从这个测试程序中看到来自命名返回值优化 (NRVO) 的复制省略,但它的输出是“地址不匹配!” 所以 NRVO 没有发生。为什么是这样?
// test.cpp
// Compile using:
// g++ -Wall -std=c++17 -o test test.cpp
#include <string>
#include <iostream>
void *addr = NULL;
class A
{
public:
int i;
int j;
#if 0
~A() {}
#endif
};
A fn()
{
A fn_a;
addr = &fn_a;
return fn_a;
}
int main()
{
A a = fn();
if (addr == &a)
std::cout << "Addresses match!\n";
else
std::cout << "Addresses do not match!\n";
}
笔记:
如果通过启用
#if
上述方法定义了析构函数,则 NRVO 确实会发生(并且在其他一些情况下也会发生,例如定义虚拟方法或添加std::string
成员)。没有定义任何方法,所以 A 是一个 POD 结构,或者在最近的术语中是一个琐碎的 class。我在上面的链接中没有看到明确的排除。
添加编译器优化(添加到一个更复杂的示例,而不仅仅是简化为空程序!)没有任何区别。
查看第二个示例的程序集表明,当我期望强制返回值优化 (RVO) 时,甚至会发生这种情况,因此上面的 NRVO 并没有通过获取 in 的地址来
fn_a
阻止fn()
。x86-64 上的 Clang、GCC、ICC 和 MSVC 显示相同的行为,表明此行为是故意的,而不是特定编译器中的错误。class A { public: int i; int j; #if 0 ~A() {} #endif }; A fn() { return A(); } int main() { // Where NRVO occurs the call to fn() is preceded on x86-64 by a move // to RDI, otherwise it is followed by a move from RAX. A a = fn(); }