请考虑以下代码:
#include <array>
class C
{
std::array<char, 7> a{};
int b{};
};
C slow()
{
return {};
}
C fast()
{
C c;
return c;
}GCC 6到9为slow()编写了非常臃肿的代码
slow():
xor eax, eax
mov DWORD PTR [rsp-25], 0
mov BYTE PTR [rsp-21], 0
mov edx, DWORD PTR [rsp-24]
mov DWORD PTR [rsp-32], 0
mov WORD PTR [rsp-28], ax
mov BYTE PTR [rsp-26], 0
mov rax, QWORD PTR [rsp-32]
ret
fast():
xor eax, eax
xor edx, edx
ret这两种功能在意义上有区别吗?Clang为这两种语言发布类似fast()的代码,而GCC 4-5的代码比6-9做得更好,但也不是很理想。
构建标志:-std=c++11 -O3
演示:https://godbolt.org/z/rPNG9o
作为GCC错误提交,基于以下反馈:bug.cgi?id=90883
发布于 2019-07-11 06:40:13
GCC的维护人员一致认为这是一个错误(错过优化),并且修复了x86_64的主干(ARM可能稍后修复):bug.cgi?id=90883
发布于 2019-06-13 11:12:53
这并不是真正完整的答案,但它可能会给出一个线索。正如我所怀疑的,对于fast和slow来说,它们的含义有细微的不同,这可能会将编译器发送到不同的路径。如果将复制构造函数设置为私有,则可以看到这一点。
#include <array>
class C
{
std::array<char, 7> a{};
public:
C(){}
private:
C(const C & c){}
};
// Compiles
C slow()
{
return {};
}
// Does not compile
C fast()
{
C c;
return c;
}即使使用copy,fast仍然要求复制构造函数在那里,因为slow正在返回一个initialization list,该initialization list由调用方显式构造返回值。它们可能会也可能不会做同样的事情,但我相信编译器必须做一些处理来确定是否是这样的。
有一篇详细的博客文章给出了关于这个主题的一些有趣的背景。
https://akrzemi1.wordpress.com/2018/05/16/rvalues-redefined/
然而,C++17中的行为已经发生了变化。
鉴于
#include <array>
class C
{
std::array<char, 7> a{};
public:
C(){}
private:
C(const C & c){}
};
C slow()
{
return {};
}
C fast()
{
return C();
}fast将无法在C++11下编译--它现在在C++17下编译
原因是return C()的含义从返回临时到显式地在调用者的框架中构造对象。
所以现在在C++17中有一个很大的区别
C fast(){
C c;
return c;
}和
C fast(){
return C();
}因为在第二个例子中,您甚至不需要一个副本或移动构造函数就可以使用。
绝对不是C++ 101
发布于 2019-06-13 16:16:07
这两个函数是等价的:返回的对象(更准确地说,是假设调用这些函数的结果对象)是通过使用其默认成员初始化器初始化每个成员来初始化的。
对于slow
{}作为初始化器(stmt.return)进行复制初始化的。=>,因此调用slow的结果对象的所有成员都使用它们的默认成员初始化器dcl.init.aggr/5.4(http://eel.is/c++draft/dcl.init.aggr#5.4)初始化。
对于fast
C(){} ([class.default.ctor]/4)。=>,因此调用slow的结果对象的所有成员都使用它们的默认成员初始化器[class.base.init]/9.1初始化。
这两个函数的结果程序集在功能上等效为。因此,Gcc生产的组件是符合标准的。
在缓慢的情况下,装配只是次优。该对象相应地返回到两个寄存器上的SystemV x86 abi : rax和rdx (edx)。首先,它将C类的对象概念归零到地址为rsp-32的堆栈上。它将a、a、b和b之间的填充字节归零。然后,它将堆栈的这个初始化部分复制到寄存器上。它将堆栈归零的方式只是次优,所有这些操作都等同于fast程序集的2 xor操作。所以这只是一个明显的错误。
https://stackoverflow.com/questions/56578196
复制相似问题