代码之家  ›  专栏  ›  技术社区  ›  fouronnes

浮点成员是否保证使用{}语法初始化为零?

  •  1
  • fouronnes  · 技术社区  · 3 年前

    在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并不清楚,两者都说:

    如果初始化器子句的数量小于成员的数量,并且基或初始化器列表完全为空,则剩余的成员和基(由于C++17)由其默认成员初始化器初始化(如果在类定义中提供),否则(由于C++14)根据通常的列表初始化规则从空列表进行复制初始化(该规则使用默认构造函数对非类类型和非聚合类执行值初始化,并对聚合执行聚合初始化)。如果引用类型的成员是这些剩余成员中的一个,则程序格式不正确。

    ( from here ),这意味着b保证为零

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

    ( from here )

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

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

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

    与相关 Why does aggregate initialization not work anymore since C++20 if a constructor is explicitly defaulted or deleted?

    0 回复  |  直到 3 年前
        1
  •  6
  •   fouronnes    3 年前

    这是C++的一个怪癖 fixed in C++20 。在此期间,您可以添加 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'
    }
    
        2
  •  5
  •   Nicol Bolas    3 年前

    因为 S 是聚集体, S{} 将执行聚合初始化。标准中关于当列表中没有初始化程序时如何初始化成员的规则是 basically what you cited :

    • 如果元素具有默认的成员初始值设定项([class.mem]),则会从该初始值设定项中初始化该元素。
    • 否则,如果该元素不是引用,则从空的初始值设定项列表([dcl.init.list])复制初始化该元素。

    所以对于b来说,这相当于 float b = {}; 。根据列表初始化的规则,我们必须获得 all the way down to 3.10 :

    否则,如果初始值设定项列表中没有元素,则对对象进行值初始化。

    值初始化将初始化 float 到0。