为什么clang没有用NRVO优化这个?

dma*_*ach 7 c++ optimization nrvo c++11

我想之所以一个相当不错的C++编译器11(铛)未优化的代码,并想知道如果这里有人有意见.

#include <iostream>
#define SLOW

struct A {
  A() {}
  ~A() { std::cout << "A d'tor\n"; }
  A(const A&) { std::cout << "A copy\n"; }
  A(A&&) { std::cout << "A move\n"; }
  A &operator =(A) { std::cout << "A copy assignment\n"; return *this; }
};

struct B {
  // Using move on a sink. 
  // Nice talk at Going Native 2013 by Sean Parent.
  B(A foo) : a_(std::move(foo)) {}  
  A a_;
};

A MakeA() {
  return A();
}

B MakeB() {  
 // The key bits are in here
#ifdef SLOW
  A a(MakeA());
  return B(a);
#else
  return B(MakeA());
#endif
}

int main() {
  std::cout << "Hello World!\n";
  B obj = MakeB();
  std::cout << &obj << "\n";
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

如果我运行这个#define SLOW注释掉并优化-s我得到

Hello World!
A move
A d'tor
0x7fff5fbff9f0
A d'tor
Run Code Online (Sandbox Code Playgroud)

这是预料之中的.

如果我在#define SLOW启用和优化的情况下运行它,-s我会得到:

Hello World!
A copy
A move
A d'tor
A d'tor
0x7fff5fbff9e8
A d'tor
Run Code Online (Sandbox Code Playgroud)

这显然不是那么好.所以问题是:

为什么我没有在"SLOW"案例中看到应用NRVO优化?我知道编译器不需要应用NRVO,但这似乎是一个常见的简单情况.

一般来说,我尝试鼓励"SLOW"风格的代码,因为我发现它更容易调试.

Die*_*ühl 13

简单的答案是:因为在这种情况下不允许应用复制省略.仅在极少数和特定情况下才允许编译器应用复制省略.该标准的引用是12.8 [class.copy]第31段:

......在下列情况下允许复制/移动操作(称为复制省略)的这种省略(可以合并以消除多个副本):

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

显然,类型B(a)不是A,即不允许复制省略.同一段落中的其他项目符号指的是throw表达式,从临时中删除副本以及异常声明等内容.这些都不适用.