C++中的聚合初始化安全性
Aggregate Initialization Safety in C++
假设我有以下结构:
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
是标量类型,则将对象设置为转换为T
的0
(零)的值- 如果
T
是非并集类类型,则每个非静态数据成员和每个基类子对象被零初始化- 如果
T
是并集类型,则对象的第一个命名数据成员)被零初始化- 如果
T
是数组类型,则每个元素被零初始化- 如果
T
是引用类型,则不执行初始化
为什么不使用
sampleData sample = { x: 1, y:2 } ;
但您仍然会遇到z
初始化为不可预测值的问题,因此最好定义一个构造函数,将所有变量设置为定义良好的值。
- 是否可以初始化不可复制类型的成员变量(或基类)
- C++使用整数的压缩数组初始化对象
- C++初始化基类
- 多成员Constexpr结构初始化
- 复制列表初始化的隐式转换的等级是多少
- 内联映射初始化的动态atexit析构函数崩溃
- 如何在C++中初始化嵌套类中的2个memeber
- 如何声明特征矩阵,然后通过嵌套循环初始化它
- 没有用于初始化C++中的变量模板的匹配构造函数
- 在未初始化映射的情况下,将值插入到映射的映射中
- C++成员初始化
- 为什么在C++中首先初始化成员类
- 同时具有"聚合初始化"和"模板推导"
- 初始化具有非默认构造函数的std::数组项的更好方法
- 是否可以在编译时初始化数组,以便在运行时不会花费时间?
- 静态变量初始化的线程安全性
- 在类型安全性的同时,初始化带有支撑的矩阵类
- 初始化COM安全性失败
- 在C++中引用未初始化变量的安全性
- C++中的聚合初始化安全性