gpt4 book ai didi

c++ - 空默认构造函数与隐式定义的不同机器代码

转载 作者:行者123 更新时间:2023-12-04 11:56:53 28 4
gpt4 key购买 nike

鉴于以下结构...

#include <type_traits>

struct C {
long a[16]{};
long b[16]{};

C() = default;
};

// For godbolt
C construct() {
static_assert(not std::is_trivial_v<C>);
static_assert(std::is_standard_layout_v<C>);

C c;
return c;
}
...gcc(x86-64 Linux 上的版本 10.2)启用优化(在所有 3 个级别)为 construct 生成以下程序集[1] :
construct():
mov r8, rdi
xor eax, eax
mov ecx, 32
rep stosq
mov rax, r8
ret
一旦我提供空的默认构造函数...
#include <type_traits>

struct C {
long a[16]{};
long b[16]{};

C() {} // <-- The only change
};

// For godbolt
C construct() {
static_assert(not std::is_trivial_v<C>);
static_assert(std::is_standard_layout_v<C>);

C c;
return c;
}
...生成的程序集更改为单独初始化每个字段,而不是原始中的单个 memset:
construct():
mov rdx, rdi
mov eax, 0
mov ecx, 16
rep stosq
lea rdi, [rdx+128]
mov ecx, 16
rep stosq
mov rax, rdx
ret
显然,这两个结构在不是微不足道的方面是等效的,而是标准布局。
只是 gcc 错过了一个优化机会,还是从 C++ 语言的角度来看还有更多?

该示例是生产代码的精简版本,其中在性能上确实存在重大差异。

[1] 神弩: https://godbolt.org/z/8n1Mae

最佳答案

虽然我同意这似乎是一个错过的优化机会,但我注意到从语言级别的角度来看有一个不同之处。隐式定义的构造函数是 constexpr而示例中的空默认构造函数不是。来自 cppreference.com :

That is, [the implicitly-defined constructor] calls the default constructors of the bases and of the non-static members of this class. If this satisfies the requirements of a constexpr constructor, the generated constructor is constexpr (since C++11).


所以作为 long数组的初始化是 constexpr ,隐式定义的构造函数也是如此。但是,用户定义的不是,因为它没有标记 constexpr .我们也可以通过尝试制作 construct 来确认这一点。示例功能 constexpr .对于隐式定义的构造函数,这没有任何问题,但对于空的用户定义版本,它无法编译,因为

<source>:3:8: note: 'C' is not an aggregate, does not have a trivial default constructor, and has no 'constexpr' constructor that is not a copy or move constructor


正如我们在这里看到的: https://godbolt.org/z/MnsbzKv1v
所以为了解决这个差异,我们可以创建空的用户定义构造函数 constexpr :
struct C {
long a[16]{};
long b[16]{};

constexpr C() {}
};
有点令人惊讶的是,gcc 现在生成了优化版本,即与默认的默认构造函数完全相同的代码: https://godbolt.org/z/cchTnEhKW
我不知道为什么,但这种差异在 constexpr在这种情况下,ness 实际上似乎有助于编译器。因此,虽然 gcc 似乎应该能够在不指定 constexpr 的情况下生成相同的代码,我想知道它可以是有益的很好。

作为对此观察的额外测试,我们可以尝试使隐式定义的构造函数非 constexpr并查看 gcc 是否无法进行优化。我能想到的一种简单方法来尝试测试它是让 C从具有非 constexpr 的空类继承默认构造函数:
struct D {
D() {}
};

struct C : D {
long a[16]{};
long b[16]{};

C() = default;
};
事实上,这会生成再次单独初始化字段的程序集。一旦我们制作 D() constexpr ,我们得到优化后的代码。见 https://godbolt.org/z/esYhc1cfW .

关于c++ - 空默认构造函数与隐式定义的不同机器代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65871288/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com