Skip to main content
added 1094 characters in body
Source Link
Andy Prowl
  • 127.2k
  • 25
  • 394
  • 455

Yes, the code is valid and does not have undefined behavior. Expressions in an initizalizer list are evaluated left-to-right and sequenced before the evaluation of the constructor of S. Therefore, your program should consistently assign value 2 to variable i.

Quoting § 8.5.4 of the C++ Standard:

"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. That is, every value computation and side effect associated with a given initializer-clause is sequenced before every value computation and side effect associated with any initializer-clause that follows it in the comma-separated list of the initializer-list."

Thus, what happens is:

  1. ++i gets evaluated, yielding i = 1 (first argument of S's constructor);
  2. ++i gets evaluated, yielding i = 2 (second argument of S's constructor);
  3. S's constructor is executed;
  4. S's conversion operator is executed, returning value 2;
  5. value 2 is assigned to i (which already had value 2).

Another relevant paragraph of the Standard is § 1.9/15, which also mentions similar examples that do have undefined behavior:

i = v[i++]; // the behavior is undefined i = i++ + 1; // the behavior is undefined 

However, the same paragraph says:

"Except where noted, evaluations of operands of individual operators and of subexpressions of individual expressions are unsequenced. [...] When calling a function (whether or not the function is inline), every value computation and side effect associated with any argument expression, or with the postfix expression designating the called function, is sequenced before execution of every expression or statement in the body of the called function."

Since 1) the evaluation of the expressions in the initializer list is sequenced left-to-right, 2) the execution of the constructor of S is sequenced after the evaluation of all expressions in the initializer list, and 3) the assignment to i is sequenced after the execution of the constructor of S (and its conversion operator), the behavior is well-defined.

Yes, the code is valid and does not have undefined behavior. Expressions in an initizalizer list are evaluated left-to-right and sequenced before the evaluation of the constructor of S. Therefore, your program should consistently assign value 2 to variable i.

Quoting § 8.5.4 of the C++ Standard:

"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. That is, every value computation and side effect associated with a given initializer-clause is sequenced before every value computation and side effect associated with any initializer-clause that follows it in the comma-separated list of the initializer-list."

Thus, what happens is:

  1. ++i gets evaluated, yielding i = 1 (first argument of S's constructor);
  2. ++i gets evaluated, yielding i = 2 (second argument of S's constructor);
  3. S's constructor is executed;
  4. S's conversion operator is executed, returning value 2;
  5. value 2 is assigned to i (which already had value 2).

Yes, the code is valid and does not have undefined behavior. Expressions in an initizalizer list are evaluated left-to-right and sequenced before the evaluation of the constructor of S. Therefore, your program should consistently assign value 2 to variable i.

Quoting § 8.5.4 of the C++ Standard:

"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. That is, every value computation and side effect associated with a given initializer-clause is sequenced before every value computation and side effect associated with any initializer-clause that follows it in the comma-separated list of the initializer-list."

Thus, what happens is:

  1. ++i gets evaluated, yielding i = 1 (first argument of S's constructor);
  2. ++i gets evaluated, yielding i = 2 (second argument of S's constructor);
  3. S's constructor is executed;
  4. S's conversion operator is executed, returning value 2;
  5. value 2 is assigned to i (which already had value 2).

Another relevant paragraph of the Standard is § 1.9/15, which also mentions similar examples that do have undefined behavior:

i = v[i++]; // the behavior is undefined i = i++ + 1; // the behavior is undefined 

However, the same paragraph says:

"Except where noted, evaluations of operands of individual operators and of subexpressions of individual expressions are unsequenced. [...] When calling a function (whether or not the function is inline), every value computation and side effect associated with any argument expression, or with the postfix expression designating the called function, is sequenced before execution of every expression or statement in the body of the called function."

Since 1) the evaluation of the expressions in the initializer list is sequenced left-to-right, 2) the execution of the constructor of S is sequenced after the evaluation of all expressions in the initializer list, and 3) the assignment to i is sequenced after the execution of the constructor of S (and its conversion operator), the behavior is well-defined.

Add missing standard text to indicate that the side-effects have a defined sequence.
Source Link
Mike Seymour
  • 255.7k
  • 30
  • 467
  • 658

Yes, the code is valid and does not have undefined behavior. Expressions in an initizalizer list are evaluated left-to-right and sequenced before the evaluation of the constructor of S. Therefore, your program should consistently assign value 2 to variable i.

Quoting § 8.5.4 of the C++ Standard:

"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. That is, every value computation and side effect associated with a given initializer-clause is sequenced before every value computation and side effect associated with any initializer-clause that follows it in the comma-separated list of the initializer-list."

Thus, what happens is:

  1. ++i gets evaluated, yielding i = 1 (first argument of S's constructor);
  2. ++i gets evaluated, yielding i = 2 (second argument of S's constructor);
  3. S's constructor is executed;
  4. S's conversion operator is executed, returning value 2;
  5. value 2 is assigned to i (which already had value 2).

Yes, the code is valid and does not have undefined behavior. Expressions in an initizalizer list are evaluated left-to-right and sequenced before the evaluation of the constructor of S. Therefore, your program should consistently assign value 2 to variable i.

Quoting § 8.5.4 of the C++ Standard:

"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"

Thus, what happens is:

  1. ++i gets evaluated, yielding i = 1 (first argument of S's constructor);
  2. ++i gets evaluated, yielding i = 2 (second argument of S's constructor);
  3. S's constructor is executed;
  4. S's conversion operator is executed, returning value 2;
  5. value 2 is assigned to i (which already had value 2).

Yes, the code is valid and does not have undefined behavior. Expressions in an initizalizer list are evaluated left-to-right and sequenced before the evaluation of the constructor of S. Therefore, your program should consistently assign value 2 to variable i.

Quoting § 8.5.4 of the C++ Standard:

"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. That is, every value computation and side effect associated with a given initializer-clause is sequenced before every value computation and side effect associated with any initializer-clause that follows it in the comma-separated list of the initializer-list."

Thus, what happens is:

  1. ++i gets evaluated, yielding i = 1 (first argument of S's constructor);
  2. ++i gets evaluated, yielding i = 2 (second argument of S's constructor);
  3. S's constructor is executed;
  4. S's conversion operator is executed, returning value 2;
  5. value 2 is assigned to i (which already had value 2).
added 4 characters in body
Source Link
Andy Prowl
  • 127.2k
  • 25
  • 394
  • 455

Yes, the code is valid and does not have undefined behavior. Expressions in an initizalizer list are evaluated left-to-right and sequenced before the evaluation of the constructor of S. Therefore, your program should consistently assign value 2 to variable i.

Quoting § 8.5.4 of the C++ Standard:

"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"

Thus, what happens is:

  1. ++i gets evaluated, yielding i = 1 (first argument of S's constructor);
  2. ++i gets evaluated, yielding i = 2 (second argument of S's constructor);
  3. S's constructor is executed;
  4. S's conversion operator is executed, returning value 2;
  5. value 2 is assigned to i (which already had value 2).

Yes, the code is valid does not have undefined behavior. Expressions in an initizalizer list are evaluated left-to-right and sequenced before the evaluation of the constructor of S. Therefore, your program should consistently assign value 2 to variable i.

Quoting § 8.5.4 of the C++ Standard:

"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"

Thus, what happens is:

  1. ++i gets evaluated, yielding i = 1 (first argument of S's constructor);
  2. ++i gets evaluated, yielding i = 2 (second argument of S's constructor);
  3. S's constructor is executed;
  4. S's conversion operator is executed, returning value 2;
  5. value 2 is assigned to i (which already had value 2).

Yes, the code is valid and does not have undefined behavior. Expressions in an initizalizer list are evaluated left-to-right and sequenced before the evaluation of the constructor of S. Therefore, your program should consistently assign value 2 to variable i.

Quoting § 8.5.4 of the C++ Standard:

"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"

Thus, what happens is:

  1. ++i gets evaluated, yielding i = 1 (first argument of S's constructor);
  2. ++i gets evaluated, yielding i = 2 (second argument of S's constructor);
  3. S's constructor is executed;
  4. S's conversion operator is executed, returning value 2;
  5. value 2 is assigned to i (which already had value 2).
added 20 characters in body
Source Link
Andy Prowl
  • 127.2k
  • 25
  • 394
  • 455
Loading
Source Link
Andy Prowl
  • 127.2k
  • 25
  • 394
  • 455
Loading