【发布时间】:2021-12-05 07:52:34
【问题描述】:
在 C++17 中,考虑S 是具有已删除默认构造函数和浮点成员的结构的情况,当 S 用空大括号初始化时,标准保证的浮点成员为零初始化?
struct A {
int x{};
};
struct S
{
S() = delete;
A a;
float b;
};
int main()
{
auto s = S{}; // Is s.b guaranteed to be zero?
}
在我看来,cppreference.com 并不清楚,两者都说:
如果初始化子句的数量小于成员的数量并且 basesor 初始化列表完全为空,则剩余的成员和基 (C++17 起)由它们的默认成员初始化器初始化,如果在类定义中提供, 否则 (C++14 起) 根据通常的列表初始化规则从空列表复制初始化聚合体)。如果引用类型的成员是这些剩余成员之一,则程序是非良构的。
(from here),这意味着b保证为零
在所有情况下,如果使用空的大括号 {} 对并且 T 是聚合类型,则执行聚合初始化而不是值初始化。
这意味着 b 不能保证为零。
还有一个讨论似乎暗示虽然不能保证,但所有已知的编译器无论如何都会进行零初始化:
标准规定当类具有用户提供或删除的默认构造函数时不执行零初始化,即使重载决议未选择该默认构造函数。如果选择了未删除的默认默认构造函数,所有已知的编译器都会执行额外的零初始化。
【问题讨论】:
-
C++20 修正了这个愚蠢的规则
-
@StoryTeller-UnslanderMonica 你有关于 C++20 修复的链接吗?
-
这是投进 C++20 的论文wg21.link/P1008R1
-
@StoryTeller-UnslanderMonica 感谢您的链接。我发现了
explicit技巧并感谢您回答自己。从技术上讲,我仍在寻找关于 b 是否会被零初始化的答案,但实际上显式技巧解决了我的真正问题! -
乐于助人。我觉得我应该指出,这个晦涩的怪癖确实有一个好处。它允许您编写不允许不确定值的聚合。考虑wandbox.org/permlink/aq1t3bMV9ORogvMy - 并注意仅禁用默认(和有问题的)初始化。我仍然同意这条规则太神秘太奇怪了,不能留下来,但这并不全是坏事。
标签: c++ c++17 language-lawyer