C ++ 20位之前的字段零初始化

时间:2018-08-23 15:36:48

标签: c++ c++11 initialization language-lawyer bit-fields

问题在下面的代码中,询问对于各个位字段成员,使用所示的值初始化语法是指零初始化还是未初始化:

struct S { // S is POD
   int a : 3;
   int b : 1;
};

S s1;
S s2{};

s1.a; // uninitialized (ok, we understand this)
s1.b; //  "

s2.a; // zero or junk?
s2.b; //  "

以下是位域的复习:https://en.cppreference.com/w/cpp/language/bit_field

在旧代码中使用丑陋的memset通常为具有许多位字段的结构创建归零构造函数,因为在构造函数初始化器列表中使用value-init语法重复每个位域成员的名称会产生难以管理的代码。即使该结构是一个很好的POD,也会这样做。如果可能的话,希望在C ++ 11中消除这种情况(不幸的是,直到C ++ 20,默认成员初始化语法才可用于位字段)。 C ++ 11是否保证使用{} -init语法对此进行零初始化?

2 个答案:

答案 0 :(得分:5)

struct S {
   int a : 3;
   int b : 1;
};

[dcl.init.aggr]/1S是一个汇总。

  

集合是具有
的数组或类([class])   (1.1)没有用户声明或继承的构造函数([class.ctor]),
  (1.2)没有私有或受保护的非静态数据成员([class.access]),
  (1.3)没有虚函数([class.virtual]),并且
  (1.4)没有虚拟,私有或受保护的基类([class.mi])。

     

[注意:聚合初始化不允许访问受保护的私有基类的成员或构造函数。 —尾注]

[dcl.init.aggr]的其余部分定义了如何初始化聚合,并且没有提及位域;因此,它们按照与其他聚合类相同的规则进行初始化。

S s{}的含义在[dcl.init.aggr]/5中定义:

  

对于非联盟聚合,不是显式初始化的元素的每个元素都按以下方式初始化:
  ...
  (5.2)否则,如果该元素不是引用,则从一个空的初始化程序列表([dcl.init.list])复制该元素。

所以,我们来看看[dcl.init.list]/3 ...,它是巨大!逐点检查,我们发现[dcl.init.list]/3.11

  

(3.11)否则,如果初始化列表中没有元素,则该对象将被值初始化。

对于标量类型,这意味着零初始化:)

  

C ++ 11是否保证使用{} -init语法对此进行零初始化?

是的

答案 1 :(得分:2)

Is Aggregate Initialization of Bit-Fields Allowed?中所述,您的结构是一个聚合。当您使用空的初始值设定项初始化集合时,集合的每个成员都是[dcl.init.aggr]/5.2

  

否则,如果该元素不是引用,则从一个空的初始化程序列表([dcl.init.list])复制该元素。

,[dcl.init.list]中的相关部分为3.11

  

否则,如果初始化列表中没有元素,则该对象将被值初始化。   [示例:

int** pp {};   // initialized to null pointer
     

-示例]

因此,将在[dcl.init]/8.4状态下初始化每个元素的值,并初始化值的相关部分

  

否则,该对象将被初始化为零。

因此我们知道每个s2中的位域将被初始化为零。