嵌套类的值初始化

时间:2017-11-03 13:28:11

标签: c++ c++11 value-initialization

通过值初始化的规则。值初始化发生:

  

1,5)使用初始化程序创建无名临时对象时   由一对空括号或括号组成(自C ++ 11起);

     

2,6)当a创建具有动态存储持续时间的对象时   new-expression,初始化器包含一对空的   括号或括号(自C ++ 11开始);

     

3,7)当一个非静态数据   使用成员初始化程序初始化成员或基类   一对空括号或括号(自C ++ 11开始);

     

4)当一个名字   变量(自动,静态或线程局部)用声明   初始化器由一对括号组成。

琐碎的例子

struct A{
    int i;
    string s;
    A(){};
};

A a{} 
cout << a.i << endl // default initialized value

没有显式声明的构造函数,并且使用默认的默认ctor //编译器生成了一个。

struct A{
    int i;
    string s;

};
A a{};
cout << a.i << endl // zero-initialized value

但是使用antoher struct。

struct A{
    int i;
    string s;

};

struct B{
    A a;
    int c;
};

B a{};
cout << a.a.i << endl // default initialized , even tho we did not , int struct B , declared A a{}.

即使没有使用{} /()构造,a.i的值也是零初始化的,这违反了规则(如果我没有记错的话)。

在结构B上使用相同的逻辑:

struct A{
    int i;
    string s;

};

struct B{
    A a;
    int c;
};

B b;
cout << b.c << endl; // default inicialized

我们按照规则行事。

最后一个例子:

struct A
{
    int i;
    A() { } 
};

struct B { A a; }; 

std::cout << B().a.i << endl;

B()。a.i在我们显式声明构造函数并且未被删除时也是零初始化的。

为什么这些值会被初始化为零?根据规则here,它们应该默认初始化而不是零初始化。

感谢您的回答。

2 个答案:

答案 0 :(得分:2)

这是A作为聚合的区别。

[dcl.init.aggr](强调我的)

  

聚合是一个数组或类(第9条),没有用户提供的构造函数(12.1),没有支撑或相等的初始值设定项   对于非静态数据成员(9.2),没有私有或受保护的非静态数据成员(第11条),

因此当A没有声明的构造函数时,A a{}具有aggregate initialization的效果

将使用空的初始化列表构造每个成员:

  

如果列表中的initializer-clause少于聚合中的成员,那么每个成员   未显式初始化应从空初始化列表

初始化

所以你得到int{}std::string{},它会将整数成员的值初始化为零。

当您提供默认构造函数时,聚合属性将丢失,int成员仍未初始化,因此访问它将被视为未定义的行为。

具体来说:

此代码在访问a.i时是未定义的行为,因为您提供了用户定义的构造函数,因此int i字段在构造后仍未初始化:

struct A{
    int i;
    string s;
    A(){};
};

A a{} ;
cout << a.i << endl;

此代码在访问b.c时显示未定义的行为,因为您未在B b上执行列表初始化:

struct B{
    A a;
    int c;
};

B b;
cout << b.c << endl;

所有其他代码都没问题,并且会对整数字段进行零初始化。在使用大括号{}的情况下,您正在执行聚合初始化

最后一个示例有点棘手,因为您正在执行值初始化。由于B是一个聚合,它会被零初始化([dcl.init]),其中:

  

每个基类   子对象是零初始化

所以你可以再次访问A子对象的整数成员。

答案 1 :(得分:0)

根据聚合初始化的规则,成员确实是初始值。

  

值初始化:

     

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

  

聚合初始化的影响是:

     
      
  1. 如果初始化程序子句的数量小于成员和基数(自C ++ 17以来)或初始化程序列表完全为空,则剩余的成员和基数(自C ++ 17起)如果在类定义中提供,则由其默认初始值设定项初始化,否则(自C ++ 14)按空列表初始化,符合通常的列表初始化规则(对非类类型执行值初始化,非具有默认构造函数的聚合类,以及聚合的聚合初始化。)如果引用类型的成员是其余成员之一,则该程序格式错误。
  2.