33

I was wondering about an initialization of the following form:

int  array[] = {
v - 1,
array[0] + 1
} ;

In the initialization of the second element, the value of the first is used, but the entire array is not yet initialized. This happens to compile with g++, but I was unsure whether this is actually portable and a well defined construct?

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
Peeter Joot
  • 7,848
  • 7
  • 48
  • 82
  • 23
    @ptomato: Because not all compilers are standard compliant - especially in weird edge-cases like this. – Björn Pollex Feb 27 '12 at 15:50
  • 20
    @ptomato In C and C++, "try it" is generally problematic. A lots of compiler have incompatible and non-standard extensions, and a lot of undefined behaviour may seem consistent in a few tests on a single platform. –  Feb 27 '12 at 15:50
  • I removed the C tag since your question mentions that you are compiling with g++ – David Heffernan Feb 27 '12 at 16:02
  • You'd probably be better off using a for-loop to initialize the array. – TheBuzzSaw Feb 27 '12 at 16:09
  • 2
    @DavidHeffernan But maybe he wants C and C++ answer if they behave differently? – Christian Rau Feb 27 '12 at 16:13
  • The real code can't use a for loop and has a much more complex sequence of initialization values (many of which reference the earlier array offset positions). – Peeter Joot Feb 27 '12 at 16:17
  • @ChristianRau But we generally ask one question at a time here – David Heffernan Feb 27 '12 at 16:19
  • constraining this question to C++ is fine (but the answer I'm interested in not be compiler specific since the code in question is built with compilers including g++, xlC, sunstudio 12.1, hpux aCC, intel, microsoft visual studio, and perhaps a few others that I am forgetting). – Peeter Joot Feb 27 '12 at 16:22
  • @DavidHeffernan Ok, I see. Since he didn't clearly say he wants a C and a C++ answer probably means he wants a C/C++ answer, in which case cleaning up tags was a good idea, anyway. – Christian Rau Feb 27 '12 at 16:24
  • 1
    @ChristianRau There's no such thing as C/C++!! – David Heffernan Feb 27 '12 at 16:29
  • This makes me thing strongly of designated initializers in C: `static int array[] = { [0] = 5, [2] = 7 };`, it did not seem to make it in C++11 though... – Matthieu M. Feb 27 '12 at 16:36
  • @DavidHeffernan That's why I reasoned it was indeed a good idea from you to clean up the tags, so that we don't encourage *C/C++* questions and answers. I hope those two exclamation marks are not directed to me, as I'm the last one to use the term *C/C++* in a serious context (maybe I should've used italics in my previous comment, too, but I didn't want it to sound even more sarcastic). – Christian Rau Feb 27 '12 at 16:41
  • @ChristianRau Sorry, that was an involuntary reflex reaction to seeing *C/C++* ;-) – David Heffernan Feb 27 '12 at 16:47

4 Answers4

18

See 3.3.2 Point of declaration:

The point of declaration for a name is immediately after its complete declarator (Clause 8) and before its initializer (if any), except as noted below. [ Example:

int x = 12;
{ int x = x; }

Here the second x is initialized with its own (indeterminate) value. —end example ]

So you are referring to the array correctly, its name is known after the =.

Then, 8.5.1 Aggregates:

An aggregate is an array or a class [...]

17: The full-expressions in an initializer-clause are evaluated in the order in which they appear.

However, I see no reference to when the evaluated values are actually written into the array, so I wouldn't rely on this and would even go so far to declare your code as not well defined.

Community
  • 1
  • 1
Sebastian Mach
  • 38,570
  • 8
  • 95
  • 130
13

As far as I can see, this is not well defined. The standard (C++11, 8.5.1/17) specifies that "The full-expressions in an initializer-clause are evaluated in the order in which they appear", but I can't see anything that requires each aggregate element to be initialised from the result of its initializer-clause before the next is evaluated.

Mike Seymour
  • 249,747
  • 28
  • 448
  • 644
1

I think this is handled by http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1343 . Initially my report was only about non-class initializers for namespace scope objects (see When exactly is an initializer temporary destroyed?), but the problem exists for aggregate elements just aswell if they are non-class. And as the additional recent note explains, even seems to exist for the entire aggregate initialization aswell, even if it is a class object, because then no constructor call happens that would enlargen the full-expression of the initializer.

If instead of int you would have used a class, and the initialization would be a constructor call, then that constructor call would be part of the same full expression that encloses the aggregate-ininitializer element, so that here the order would be OK and your code would be well-defined.

Johannes Schaub - litb
  • 496,577
  • 130
  • 894
  • 1,212
1

Can a (C/C++) array initialization reference itself?

This is also valid C code.

C has some correspondent paragraph (emphasis mine).

(C99, 6.2.1p7) "Structure, union, and enumeration tags have scope that begins just after the appearance of the tag in a type specifier that declares the tag. Each enumeration constant has scope that begins just after the appearance of its defining enumerator in an enumerator list. Any other identifier has scope that begins just after the completion of its declarator."

ouah
  • 142,963
  • 15
  • 272
  • 331