C++中的聚合初始化安全性

Aggregate Initialization Safety in C++

本文关键字:初始化 安全性 C++      更新时间:2023-10-16

假设我有以下结构:

struct sampleData
{
       int x;
       int y;
};

当使用时,我想将sampleData类型的变量初始化为已知状态。

sampleData sample = { 1, 2 } 

稍后,我决定需要在sampleData结构中存储额外的数据,如下所示:

struct sampleData
{
       int x;
       int y;
       int z;
};

据我所知,我的预z数据结构中遗留的两个字段初始化仍然是一个有效的语句,并且将被编译。,用默认值填充缺失的字段。

这种理解正确吗?我最近一直在使用Ada,它也允许聚合初始化,但它会将类似的问题标记为编译错误。假设我对上面C++代码的假设是正确的,是否有一种语言构造会将丢失的初始化值识别为错误?

只有聚合类才支持以这种方式初始化变量。

若您添加了构造函数,那个么问题就消失了,但您需要稍微更改语法,并且您将失去在union中存储struct的能力(以及其他功能)。

struct sampleData
{
    sampleData(int x, int y) : x(x), y(y) {}
    int x;
    int y;
};
sampleData sample( 1, 2 );

添加z(并更改构造函数)会将sample( 1, 2 )标记为编译错误。

是的,您从初始化列表中删除的任何元素都将初始化为零(对于POD标量类型)或使用其默认构造函数(对于类)。

此处引用C标准中的相关语言:

[6.7.8.21]如果大括号列表中的初始值设定项少于聚合的元素或成员,或者用于初始化已知大小数组的字符串文字中的字符少于数组中的元素,则聚合的其余部分应与具有静态存储持续时间的对象一样隐式初始化。

我相信有人比我更有动力在C++规范中找到相应的语言。。。

注意,这意味着POD标量元素被初始化,就像您写"=0"一样。这意味着它将正确地将指针初始化为NULL,并将浮点值设置为0.0,即使它们的表示形式并非全部为零字节。它还意味着它是递归工作的;如果您的结构包含一个结构,那么内部结构也将被正确初始化。

作为Nemo用C标准回答的后续,以下是C++03标准所说的:

§8.5.1/7:

如果列表中的初始化程序少于聚合中的成员,则每个未显式初始化的成员都应进行值初始化。

§8.5/5:

值初始化,类型为T的对象意味着:

  • 如果T是具有用户声明的构造函数的类类型,则调用T的默认构造函数(如果T没有可访问的默认构造函数,则初始化形式不正确)
  • 如果T是没有用户声明构造函数的非并集类类型,则T的每个非静态数据成员和基类组件都被值初始化
  • 如果T是数组类型,则对每个元素进行值初始化
  • 否则,对象初始化为零

零初始化,类型为T的对象意味着:

  • 如果T是标量类型,则将对象设置为转换为T0(零)的值
  • 如果T是非并集类类型,则每个非静态数据成员和每个基类子对象被零初始化
  • 如果T是并集类型,则对象的第一个命名数据成员)被零初始化
  • 如果T是数组类型,则每个元素被零初始化
  • 如果T是引用类型,则不执行初始化

为什么不使用

sampleData sample = { x: 1, y:2 } ;

但您仍然会遇到z初始化为不可预测值的问题,因此最好定义一个构造函数,将所有变量设置为定义良好的值。