首页 > 解决方案 > 浮点成员是否保证使用 {} 语法初始化为零?

问题描述

在 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 起)根据通常的列表初始化规则从空列表复制初始化(它使用默认构造函数对非类类型和非聚合类执行值初始化,并对聚合执行聚合初始化)。如果引用类型的成员是这些剩余成员之一,则程序格式错误。

从这里),这意味着 b 保证为零

在所有情况下,如果使用空的大括号 {} 对并且 T 是聚合类型,则执行聚合初始化而不是值初始化。

从这里

这意味着 b 不能保证为零。

还有一个讨论似乎暗示虽然不能保证,但所有已知的编译器无论如何都会进行零初始化:

该标准规定,当类具有用户提供或删除的默认构造函数时,不执行零初始化,即使重载决议未选择该默认构造函数。如果选择了未删除的默认默认构造函数,所有已知的编译器都会执行额外的零初始化。

如果构造函数显式默认或删除,为什么自 C++20 以来聚合初始化不再起作用有关?

标签: c++c++17language-lawyer

解决方案


这是在 C++20 中修复的 C++的一个怪癖。同时,您可以添加explicit到已删除的默认构造函数中以强制结构变为非聚合,并使您的代码有保证的编译错误:

struct A {
  int x{};
};

struct S
{
  explicit S() = delete;
 
  const A a;
  const float b;
};

int main()
{
  auto s = S{}; // error: call to deleted constructor of 'S'
}

推荐阅读