首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么clang不对NRVO进行优化?

为什么clang不对NRVO进行优化?
EN

Stack Overflow用户
提问于 2013-12-18 04:58:11
回答 2查看 1.1K关注 0票数 8

我试图解释为什么一个相当好的C++ 11编译器(clang)没有优化这段代码,并想知道这里是否有人有自己的观点。

代码语言:javascript
复制
#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;
}

如果我使用#define SLOW进行注释并使用-s进行优化,那么

代码语言:javascript
复制
Hello World!
A move
A d'tor
0x7fff5fbff9f0
A d'tor

这是意料之中的。

如果我在启用#define SLOW并使用-s进行优化的情况下运行该程序,则会得到:

代码语言:javascript
复制
Hello World!
A copy
A move
A d'tor
A d'tor
0x7fff5fbff9e8
A d'tor

这显然不太好。所以问题是:

为什么我没有看到NRVO优化应用在“慢”的情况下?我知道编译器不需要应用NRVO,但这似乎是一个常见的简单情况。

一般来说,我试图鼓励使用“缓慢”样式的代码,因为我发现调试起来容易得多。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2013-12-18 05:17:19

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

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

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

显然,B(a)的类型不是A,即不允许复制省略。同一段中的其他符号引用诸如throw表达式、从临时声明和异常声明中选择副本等内容。这些都不适用。

票数 13
EN

Stack Overflow用户

发布于 2014-01-05 23:45:23

在慢速路径中看到的复制不是由于缺少RVO,而是因为在B(MakeA())中,"MakeA()“是一个rvalue,而在B(a)中,"a”是一个lvalue。

为了澄清这一点,让我们修改慢速路径,以指示MakeA()在何处完成:

代码语言:javascript
复制
#ifdef SLOW
  A a(MakeA());
  std::cout << "---- after call \n";
  return B(a);
#else

产出如下:

代码语言:javascript
复制
Hello World!
---- after call 
A copy
A move
A d'tor
A d'tor
0x7fff5a831b28
A d'tor

,这表明没有在

代码语言:javascript
复制
A a(MakeA());

因此,RVO确实发生了。

删除所有副本的修复程序是:

代码语言:javascript
复制
return B(std::move(a));
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/20649951

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档