2015-06-27 77 views
22

考虑下面的代码中,我们基于对D另一部分初始化的D部分:数组成员是否可以自我初始化?

struct c { 
    c() : D{rand(), D[0]} {} 
    int D[2]; 
}; 

int main() { 
    c C; 
    assert(C.D[0] == C.D[1]); 
} 

在上述程序明确定义?我们可以安全地使用同一个数组的一部分来初始化它的另一部分吗?

+5

我的第一个想法是“不要”。我的第二个想法是“初始化程序列出havr命令gurantees”。我的第三个想法是“初始化发生在论证评估之后,不是吗?” – Yakk

回答

11

数组成员是否可以自我初始化?

是。

struct c { 
    int a[3]; 
    c() : a{4, a[0], 3} {} // a[0] is initialized to 4. 
          // a[1] is initialized to whatever a[0] is. (4) 
          // a[2] is initialized to 3. 
}; 

但考虑这个例子:

struct c { 
    int a[3]; 
    c() : a{a[1], 4, a[1]} {} // a[0] is initialized to whatever a[1] is.(Garbage value) 
           // a[1] is initialized to 4. 
           // a[2] is initialized to what a[1] is now (4). 
}; 

在这里,在a的第一个元素将是任何值是a[1], 这将很可能是垃圾的价值。 第二个元素被初始化为4,第三个元素被初始化为 ,现在是a[1],它的值是4

此外,当你不列出未列出的{}, 元素中的阵列中的所有元素,将被默认初始化:

struct c { 
    int a[5]; // notice the size 
    c() : a{a[1], 2, 3, 4}{} // a[0] will get value that is in a[1] 
           // but since a[1] has garbage value, 
           // it will be default initialized to 0. 
           // a[1] = 2 
           // a[2] = 3 
           // a[3] = 4 
           // a[4] is not listed and will get 0. 
}; 

然而,上市已经初始化的元素会给你你想要的价值。
使用上面的例子:

struct c { 
    int a[5]; 
    c() : a{1, a[0], 3, 4}{} // a[0] = 1 
           // a[1] = 1 
           // a[2] = 3 
           // a[3] = 4 
           // a[4] is not listed and will get 0. 
}; 
16

当聚合(包括数组)从一个支撑列表初始化时,每个聚合元素都从列表的相应元素(“增加下标或成员顺序”)进行初始化。尽管我找不到一个确切的规则,说每个元素的初始化都是在前一个元素之后进行排序的,但标准中有一个例子清楚地表明这是预期的意思。该例子是在[dcl.init.aggr]:

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

初始化ss.a1ss.b"asdf"ss.c与表单int{}(即,0)的表达式的值,和ss.dss.b[ss.a]的值(即,’s’

+3

[dcl.init.list]/4:“在加载初始化列表的初始化程序列表中,初始化程序子句,包括从包 扩展(14.5.3)产生的任何结果子句,按照也就是说,与给定的初始化子句相关的每个值计算和副作用在每个值计算之前被排序,并且在与初始值设定项的逗号分隔列表中的任何初始化子句相关联的任何初始值 - 清单“。 – Casey

+2

@Casey:副作用是否包括聚合成员的初始化? –

+0

初始化当然是一个副作用,声称副作用与给定的*初始化子句*相关并不是不合理的。鉴于没有任何相反的语言,我认为这是预期的解释。 – Casey

0

它不是写一个很好的做法因为当构造函数运行时,不需要首先执行rand()将执行 然后D [0],这一切都取决于编译器,D [0]可能是 首先执行,在这种情况下,d [ 1]将包含垃圾值。它 完全取决于编译器,它可以先编译第二个参数 ,然后第一个参数或反之亦然,执行此 语句可能会导致未知行为。

+3

标准很清楚'rand()'在'D [0]'之前被调用,所以你是不正确的:il不是finction调用,你会正确的。在读取'D [0]'之前初始化'D [0]'还不太清楚。 – Yakk

+1

我目前正在学习C++,我已经阅读了C++ primer中的这种行为,我使用的是一本书,在书中明确指出哪个参数首先被执行是未知行为,并且它不是一个很好的做法,关于初始化的其他参数 –

+3

是来自某处的引用,或者你为什么将它放在块引用中?如果是这样,请正确归因(标题,页面,作者,网址等)。 – Bergi

2

根据cppreference.com

集合初始化的效果是:

每个数组元素或非静态类成员,在类定义数组 标/出现的顺序,从 初始化器列表的相应子句复制初始化。

你的代码似乎很好。 但有点混淆。

+0

为什么会令人困惑? – emlai

+0

在我看来,它降低了可读性,许多人不知道他们会按顺序进行评估。 – deepmax

相关问题