【发布时间】:2021-10-01 10:04:06
【问题描述】:
考虑这个例子,结构 S 被构造并作为参数传递给函数:
struct S
{
S() {}
float vals[64];
};
inline S makeS() { return {}; }
void foo(const S &);
void bar() { foo( makeS() ); }
查看编译器生成的程序集 (https://godbolt.org/z/odoPr9836),它非常小(正如预期的那样)。
但是,如果我们从 S 中删除构造函数,从而将其转换为聚合 (https://godbolt.org/z/qEWKbx5Ps),则程序集的体积会大很多倍。
甚至似乎 MSVC 不执行强制 RVO 并复制聚合:
...
movups XMMWORD PTR [rcx-128], xmm0
movups xmm0, XMMWORD PTR [rax-96]
movups XMMWORD PTR [rcx-112], xmm1
movups xmm1, XMMWORD PTR [rax-80]
...
由此可知,与普通 C++ 类或结构相比,在实践中使用聚合产生的优化代码要少得多?
【问题讨论】:
-
Relative stackoverflow.com/questions/47853659/… 聚合初始化基本上执行元素方式的复制初始化。
-
“它遵循...” - 不,它没有遵循。您仅看到差异,因为您的比较不公平。根据定义,聚合初始化必须初始化每个成员。而那些你不提供的将从
{}递归初始化。这意味着您 要求 将数组清零。为了进行公平比较,也可以尝试inline S makeS() { S s; return s; },因此默认初始化是在您的聚合(及其子对象上执行的,就像您的 c'tor 一样)。 C++ 对专家非常友好。一个令人不快的事实,但你有它。 -
同什么?当强制执行默认初始化时,我会看到带有或不带有构造函数的相同程序集。您似乎仍然没有将苹果与苹果进行比较。
-
@StoryTeller 我不认为这样做是一样的。这是未定义的行为,因为您复制了尚未初始化的值,对吧?
-
OP 对他们的构造函数做了什么。当然,当编译器在幕后魔术时,它是正式的左值到右值转换吗?我不确定。
标签: c++ return-value-optimization