在 C++ 中使用聚合的性能损失是什么?

问题描述

考虑使用结构 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++ 类或结构相比,在实践中使用聚合产生的最佳代码要少得多?

解决方法

你的比较是不公平的。


struct S
{
    S() {}
    float vals[64];
};

这样,您实际上并没有初始化 vals。为了公平比较,它应该是:

struct S
{
    S() : vals{} {}
    float vals[64];
};

或者简单地使用:

S() = default;

现在 gcc 和 clang 都为它们生成相同的代码,其中 msvc 为 makeS 生成相同的代码:https://godbolt.org/z/rezxTorGs


也有人请纠正我:

struct S
{
    float vals[64];
};

inline S makeS() { return {}; }

我相信这个使用默认构造函数而不是聚合初始化。

您可能需要使用 return {{}};return {.vals = {}}; 来强制聚合初始化。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...