What is aggregate initialization?
Asked Answered
E

2

37

The section "Array Initialization" in Chapter 4, page 231 of "Thinking in Java, 2nd Edition" has this to say:

Initializing arrays in C is error-prone and tedious. C++ uses aggregate initialization to make it much safer. Java has no “aggregates” like C++, since everything is an object in Java. It does have arrays, and these are supported with array initialization.

Why is it error prone and tedious in C? What does it mean by aggregate initialization and why is it safer? I came across the chapter "Aggregate initialization" in Bruce Eckel's "Thinking in C++" (2nd Ed.), but it doesn't convince me of anything.

Enlistment answered 18/7, 2013 at 1:9 Comment(7)
Perhaps it means the author has a financial interest in convincing people to learn Java instead of C, because he isn't selling books on C.Gelation
C has aggregate initialisation in the form of compound literals, not sure what is meant by the description above. But I wouldn't regard it as 'error-prone'.Ulda
The author thinks C has no changes since C89, perhaps.Inhabiter
@YuHao I thought array initializers were there in C89 as well, just not struct ones... At least, this compiles for me with --std=c89.Bondie
@Bondie What I mean is that C99 introduced designated initializer and compound literals, which are very useful and elegant.Inhabiter
Voting to close because without knowing what the author of the book meant by "error-prone" and "safer" this is begging the question at best.Bondie
A small comment on "...since everything is an object in Java". Everything is not an object in Java, since it has primitive types. In contrast, in C# everything is an object; "primitive types" are structs, so 5.ToString() is perfectly valid in C#, but not in Java.Astrogate
C
34

First of all, to answer the main question, aggregate initialization means the use of brace-enclosed initializer lists to initialize all members of an aggregate (i.e. an array or struct [in C++, only certain types of structs count as aggregates]).

Obviously,

int ar[] = { 1 , 2 };

is safer than

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

because the latter gives ample opportunity for typos and other errors in the indices of the individual elements to be initialized.

Looking at today's C and C++, it's unclear to me why the author makes a distinction between C and C++. Both languages enable aggregate initialization for arrays.

One possibility is that the author referred to old versions of the C Standard. Notably, in ANSI C (C89) an important restriction applied to the use of aggregate initialization: All initializers had to be constant expressions:

/* 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 }; }

This is due to 3.5.7 in C89 (quoting from the draft I found here):

All the expressions in an initializer for an object that has static storage duration or in an initializer list for an object that has aggregate or union type shall be constant expressions.

This clearly limits the usefulness of aggregate initialization (and even in 1989, I believe many compilers implemented extensions to enable aggregate initialization also for non-constant expressions).

Later versions of the C Standard did not have this restriction, and the standardized versions of C++ (starting with C++98), I believe, never had any such restriction.

I can only speculate, but perhaps this is what the author had in mind?

Chickenhearted answered 18/7, 2013 at 1:44 Comment(1)
I think he is referring to int ar[3] = {};, which is valid in C++ but not in C. int ar[3] = {0}; works in both, of course... But change it to struct S s[3] = {}; to get a feel for what C++ "aggregate initialization" is really about.Lishalishe
K
1

I am assuming that the author is warning you about the lack of enforcing size constraints in C and C++. In C and C++, arrays decay down to pointers to their first element. It then uses pointer arithmetic to find the element you are refering to by index. Since arrays are not objects and the compiler makes no effort to store their size, there are no length checks. In java, arrays are objects and therefore their size is known. This size can be checked against, which safe guards the developer from accessing memory which doesn't belong to him/her when overstepping the bounds of the array.

I find it strange the statement 'C++ uses aggregate initialize to make it much safer' was even used in this context.

Aggregate initialization, which is common to most modern languages, is as follows

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

This type of initialization assumes you know the size of the array beforehand and its contents. This type of initialization safe guards one from over stepping the boundary and provides for initializing an array with set values. Maybe in this case the author has in a mind a developer who declared a static C array of size 5. This developer then creates a loop to initialize its content but oversteps the boundary of the array by one, writing to memory that is not his/hers.

Knave answered 18/7, 2013 at 1:23 Comment(4)
Isn't int intArray[3] = {1,2,3}; allowed in C as well?Enlistment
@Paul: int intArray[] = {1,2,3}; -- look, size calculated by compiler, no overrun possible. But even when you do specify the size, the compiler will catch if there are too many initializers.Gelation
@Ben: Thanks for the example. I should have included that as well.Knave
Arrays are certainly objects.Anoint

© 2022 - 2024 — McMap. All rights reserved.