【问题标题】:Structure aggregate initialization with less clauses, why does it initialize everything?使用较少子句的结构聚合初始化,为什么它会初始化所有内容?
【发布时间】:2014-10-08 11:47:06
【问题描述】:

如果我有一个常见的 linux 结构,例如:

struct sockaddr_in
{
  sa_family_t    sin_family;   
  in_port_t      sin_port;     
  struct in_addr sin_addr;     

  unsigned char  __pad[__SOCK_SIZE__ - sizeof(short int)
                        - sizeof(unsigned short int) - sizeof(struct in_addr)];
};
#define sin_zero        __pad

然后我执行聚合初始化:

struct sockaddr_in my_addr = { 0 };

为什么这会将每个成员都初始化为 0?

我的意思是:文档说:

如果初始化子句的数量小于 成员或初始化子句完全为空,其余的 成员由它们的大括号或等号初始化器初始化,如果 在类定义中提供,否则 (C++14 起) 为空 列表,它执行值初始化。

为了简单起见:为什么这段代码会打印 0?

struct sockaddr_in my_addr = {2, 2}; // initialize sin_family and sin_port to 2, everything else value-initialized

my_addr = {0};

std::cout << my_addr.sin_port; // Why is this 0?

【问题讨论】:

  • {0} 使用该初始化程序创建一个临时的 sockaddr_in,然后 = 复制整个临时文件。
  • 如果初始化器的数量少于要初始化的成员,其余成员将被初始化为static(即使用 0)。
  • @TheParamagneticCroissant,C 就是这种情况,但对于 C++,并非所有类型都可以用 0 初始化。它们是值初始化的,这可能会将它们设置为零,但默认构造函数可以做一些不同的事情.
  • @T.C.没有为聚合初始化或 C++11 列表初始化创建临时文件,即使它在语法上是 复制初始化。参见 [dcl.init] p17,项目符号 17.6.2。相反,my_addr 的成员直接从列表元素复制初始化
  • @T.C.啊,我以为您指的是问题前面的struct sockaddr_in my_addr = { 0 }; sn-p。我应该注意到你说的是{0} 而不是{ 0 } :-)

标签: c++ initialization list-initialization


【解决方案1】:

这在 draft C++14 standard 部分 8.5.4 List-initialization 中有介绍,其中说:

类型 T 的对象或引用的列表初始化定义如下:

包括:

如果 T 是聚合,则执行聚合初始化 (8.5.1)。

并有以下示例:

struct S2 {
    int m1;
    double m2, m3;
}
S2 s21 = { 1, 2, 3.0 }; // OK
S2 s22 { 1.0, 2, 3 }; // error: narrowing
S2 s23 { }; // OK: default to 0,0,0

8.5.1 聚合 说:

如果列表中的初始化子句少于 聚合成员,然后是每个成员 未显式初始化应从其初始化 大括号或相等初始化器,或者,如果没有 大括号或相等初始化器,来自一个空的初始化器列表(8.5.4)。 [ 示例:

struct S { int a; const char* b; int c; int d = b[a]; };
S ss = { 1, "asdf" };

用 1 初始化 ss.a,用“asdf”初始化 ss.b,用 an 的值初始化 ss.c int{} 形式的表达式(即 0)

请注意,8.5.4 在 C++11 中略有不同,它表示:

类型 T 的对象或引用的列表初始化定义为 如下:

  • 如果初始化列表没有元素并且 T 是一个类 带有默认构造函数的类型,对象是值初始化的。

  • 否则,如果 T 是聚合,则执行聚合初始化 (8.5.1)。

【讨论】:

    【解决方案2】:

    为什么这会将每个成员都初始化为 0?

    因为这是 C 在初始化结构时所做的事情,而 C++ 在聚合初始化时也是如此以实现兼容性。

    C 这样做是因为它更方便(它通常是你想要的成员,但你没有给出明确的值)并且更安全(它不会留下危险的未初始化变量)。

    如果你真的希望结构的其他成员保持未初始化,你可以这样做:

    struct sockaddr_in s; // entirely uninitialized
    s.sin_family = 0;     // only initialize one member
    

    【讨论】:

    • 请注意,此建议仅适用于 sin_family 是整数; s.sin_addr = 0; 无法正常工作。
    • @MattMcNabb,您可以在 C++03 中使用 s.sin_addr = in_addr(); 或在 C++11 中使用 s.sin_addr = {};。在 C 中,您可以从左值复制它,例如static struct in_addr a; s.sin_addr = a;
    猜你喜欢
    • 2016-06-23
    • 2020-10-22
    • 2016-12-18
    • 2023-03-10
    • 1970-01-01
    • 2021-10-26
    • 2022-01-05
    • 2020-03-18
    相关资源
    最近更新 更多