c++ 什么是聚合初始化?

cld4siwp  于 2023-10-21  发布在  其他
关注(0)|答案(2)|浏览(148)

《Java思维,第2版》第4章第231页的“数组”一节是这样说的:
在C中初始化数组容易出错,而且很繁琐。C使用聚合初始化使其更安全。Java没有像C那样的“聚合”,因为在Java中一切都是对象。它确实有数组,并且数组初始化支持这些数组。
为什么在C中容易出错和冗长?聚合初始化是什么意思?为什么它更安全?我在布鲁斯·埃克尔的《用C++思考》(第2版)中遇到了the chapter "Aggregate initialization",但它并没有说服我任何东西。

csga3l58

csga3l581#

首先,为了回答主要问题,聚合初始化意味着使用花括号括起的初始化器列表来初始化聚合的所有成员(即,数组或结构[在C++中,只有特定类型的结构才算聚合])。
显然

int ar[] = { 1 , 2 };

更安全

int ar[2];
ar[0] = 1;
ar[1] = 2;

因为后者为待初始化的各个元素的索引中的打字错误和其它错误提供了充足的机会。
看看今天的C和C++,我不清楚作者为什么要区分C和C++。这两种语言都支持数组的聚合初始化。
一种可能性是作者引用了C标准的旧版本。值得注意的是,在ANSI C(C89)中,对聚合初始化的使用有一个重要的限制:所有的初始化器必须是常量表达式:

/* This is possible in C89: */
f(int i)
{ int ar[] = { 1 , 2 }; }

/* But this is not
   (because i is not a constant expression):
*/
f(int i)
{ int ar[] = { i , i+1 }; }

这是由于C89中的3.5.7(引用我找到的here草稿):
具有静态存储期的对象的初始化器中的所有表达式,或具有聚合或联合类型的对象的初始化器列表中的所有表达式都必须是常量表达式。
这显然限制了聚合初始化的有用性(甚至在1989年,我相信许多编译器实现了扩展,以支持非常量表达式的聚合初始化)。
后来的C标准版本没有这个限制,而C的标准化版本(从C98开始),我相信,从来没有任何这样的限制。
我只能推测,但也许这就是作者的想法?

ohtdti5x

ohtdti5x2#

我假设作者是在警告你在C和C中缺乏强制的大小约束。在C和C中,数组衰减为指向其第一个元素的指针。然后,它使用指针算法通过索引找到您要访问的元素。由于数组不是对象,编译器也不会存储它们的大小,所以没有长度检查。在java中,数组是对象,因此它们的大小是已知的。这个大小可以被检查,这可以保护开发人员在超出数组边界时访问不属于他/她的内存。
我觉得奇怪的是,“C++使用聚合初始化使其更安全”的语句甚至被用在了这种上下文中。
聚合初始化是大多数现代语言所共有的,如下所示

int intArray[3] = {1,2,3};
int int2DArray[2][2] = {{1,2}, {3,4}};

这种类型的初始化假定您事先知道数组的大小及其内容。这种类型的初始化可以防止越过边界,并提供使用设置值初始化数组。也许在这种情况下,作者在脑海中有一个开发人员,他声明了一个大小为5的静态C数组。这个开发人员然后创建一个循环来初始化它的内容,但是超出了数组的边界,写入了不是他/她的内存。

相关问题