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

发布于 2024-11-14 10:09:41 字数 537 浏览 5 评论 0原文

假设我有以下结构:

struct sampleData
{
       int x;
       int y;
};

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

sampleData sample = { 1, 2 } 

后来,我决定需要将其他数据存储在我的 sampleData 结构中,如下所示:

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

据我了解,我的前 z 数据结构中留下了两个字段初始化仍然是有效的语句,并且将被编译。用默认值填充缺少的字段。

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

Suppose I have the following struct:

struct sampleData
{
       int x;
       int y;
};

And when used, I want to initialize variables of sampleData type to a known state.

sampleData sample = { 1, 2 } 

Later, I decide that I need additional data stored in my sampleData struct, as follows:

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

It is my understanding that the two field initialization left over from my pre-z data structure is still a valid statement, and will be compiled., populating the missing fields with default values.

Is this understanding correct? I have been working recently in Ada, which also allows aggregate initialization, but which would flag a similar issue as a compilation error. Assuming that my assumptions about the C++ code above are correct, is there a language construct which would recognize missing initialization values as an error?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

国际总奸 2024-11-21 10:09:42

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

如果您添加构造函数,那么问题就会消失,但是您需要稍微更改语法,并且您将失去将 struct 存储在 union 中的能力(除其他外)。

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

sampleData sample( 1, 2 );

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

Initialising variables that way is only supported with Aggregate Classes.

If you add constructor(s) then then problem goes away, but you'll need to change the syntax a little and you lose the ability to store the struct in a union (among other things).

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

sampleData sample( 1, 2 );

Adding z (and changing the constructor) will mark sample( 1, 2 ) as a compile error.

咿呀咿呀哟 2024-11-21 10:09:42

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

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

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

我确信有人比我更有动力,可以在 C++ 规范之一中找到相应的语言...

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

Yes, any elements you leave off of the initialization list will be initialized to zero (for POD scalar types) or using their default constructor (for classes).

The relevant language from the C standard is quoted here:

[6.7.8.21] If there are fewer initializers in a brace-enclosed list than there are elements or members of an aggregate, or fewer characters in a string literal used to initialize an array of known size than there are elements in the array, the remainder of the aggregate shall be initialized implicitly the same as objects that have static storage duration.

I am sure someone more motivated than I could find the corresponding language in one of the C++ specs...

Note that this implies that POD scalar elements are initialized as if you wrote "= 0". Which means it will correctly initialize pointers to NULL and floats to 0.0 even if their representations do not happen to be all-zero bytes. It also implies that it works recursively; if your struct contains a struct, the inner struct will be properly initialized as well.

全部不再 2024-11-21 10:09:42

作为 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 是引用类型,则不执行初始化。

As a followup to Nemo's answer with the C standardese, here is what the C++03 standard says:

§8.5.1/7:

If there are fewer initializers in the list than there are members in the aggregate, then each member not explicitly initialized shall be value-initialized.

§8.5/5:

To value-initialize an object of type T means:

  • if T is a class type with a user-declared constructor, then the default constructor for T is called (and the initialization is ill-formed if T has no accessible default constructor);
  • if T is a non-union class type without a user-declared constructor, then every non-static data member and base-class component of T is value-initialized;
  • if T is an array type, then each element is value-initialized;
  • otherwise, the object is zero-initialized

To zero-initialize an object of type T means:

  • if T is a scalar type, the object is set to the value of 0 (zero) converted to T;
  • if T is a non-union class type, each nonstatic data member and each base-class subobject is zero-initialized;
  • if T is a union type, the object’s first named data member) is zero-initialized;
  • if T is an array type, each element is zero-initialized;
  • if T is a reference type, no initialization is performed.
贱人配狗天长地久 2024-11-21 10:09:42

为什么不使用

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

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

Why not use

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

?

But you'd still run into the problem of z being initialized to an unpredictable value, so it's better to define a constructor which sets all variables to well defined values.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文