Vincent
Vincent

Reputation: 60371

Interdependent initialization with commas?

Is the following perfectly defined:

int x = 42, y = x;

i.e. strictly equivalent to:

int x = 42;
int y = x;

EDIT : the question is not about style (I know that it's wrong...), the question is "theoretical"

Upvotes: 12

Views: 1199

Answers (2)

Shafik Yaghmour
Shafik Yaghmour

Reputation: 158469

This question came up in comp.lang.c++.moderated a long time ago under the topic init-declarator-list analysis order and the conclusion there was Yes.

Although I see the full-expression argument but I do not see the order of evaluation argument. So I think this is unspecified.

The relevant part of the question is:

In this declaration and definition:

int a = 2, b = a;

Is it guaranteed that b will always be initialized as 2 ? If yes, then can we say that a = 2 is always analysed(or evaluated?) before b = a ?

and the relevant part of the answer is:

Yes. Strictly stated, the observable behavior of the program must be as if all of the side effects of the 'a = 2' part of the declaration took place before the evaluation of the 'b = a' part starts. (In practice, of course, in this simple example, a compiler could assign 2 to both a and b in any order, or even in parallel, because doing so would result in the same observable behavior.)

and further down:

In this particular case, however, it does separate the declarator list into separate declarators; each declarator contains a complete expression, and the declarators are evaluated in order.

Update

What makes each init-declator a full expression is subtle but as far as I can tell follows the same logic I used in Are multiple mutations of the same variable within initializer lists undefined behavior pre C++11. In this case we start from the grammar defined in ection 8:

init-declarator-list:
  init-declarator
  init-declarator-list , init-declarator
init-declarator:
  declarator initializeropt

The next point of focus is the initializer grammar which is covered in section 8.5:

initializer:
  brace-or-equal-initializer
  ( expression-list )
brace-or-equal-initializer:
  = initializer-clause
  braced-init-list
initializer-clause:
  assignment-expression
  braced-init-list

In both cases we have = initializer-clause which bring us to assignment-expression which if we follow the grammar in section 5 bring us back to primary-expression which can give us either a literal or id-expression.

So we do indeed have full-expressions separated by a grammatical comma so we have:

int x = 42, y = x;
          ^      ^
          |      end full-expression
          end full-expression

and according to section 1.9 paragraph 14 we see that:

Every value computation and side effect associated with a full-expression is sequenced before every value computation and side effect associated with the next full-expression to be evaluated.8.

As for the order of evaluation, I think this is not specified, the same logic that applies to defect report 430 for initializer lists would seem to apply here as well. In C++11 the language for initializer lists was fixed with the following addition in section 8.5.4:

Within the initializer-list of a braced-init-list, the initializer-clauses, including any that result from pack expansions (14.5.3), are evaluated in the order in which they appear. [...]

there is no such equivalent for initializer.

Upvotes: 5

Dimitrios Bouzas
Dimitrios Bouzas

Reputation: 42899

The correct answer is that

int x = 42, y = x;

and

int x = 42;
int y = x;

are usually equivalent (not strictly).


Considering the standard § 8 Declarators [dcl.decl]:

3 Each init-declarator in a declaration is analyzed separately as if it was in a declaration by itself.

and in the footnote [100] further explains:

A declaration with several declarators is usually equivalent to the corresponding sequence of declarations each with a single declarator. That is

T D1, D2, ... Dn;

is usually equivalent to

T D1; T D2; ... T Dn;

where T is a decl-specifier-seq and each Di is an init-declarator.

  • The above guarantees that x = 42 and y = x will be evaluated separately. However, as @Praetorian correctly pointed out in the comments, footnotes are not normative.

  • This means that the order of evaluation is not well defined and an implementer could as well implement the evaluation of the declarations in the reverse order (i.e,. T Dn; ...T D2; T D1;).

  • One might argue that the comma operator is guaranteed left to right evaluation. However, this not the case. According to the K & R [K & R II, 3.6 p.63], that also applies to C++:

The commas that separate function arguments, variables in declarations, etc., are not comma operators, and do not guarantee left to right evaluation.

Upvotes: 11

Related Questions