Is aggregate member copy-initialization associated with the corresponding initializer-clause?

66 views
Skip to first unread message

Edward Catmur

unread,
Feb 24, 2015, 10:05:07 AM2/24/15
to std-dis...@isocpp.org
From http://stackoverflow.com/q/21294831/567292:

struct S { int i; int j; };
int f() { S s{5, s.i}; return s.j; }

Is this defined behavior?

[dcl.init.aggr]/2 has:
When an aggregate is initialized by an initializer list, as specified in 8.5.4, the elements of the initializer list
are taken as initializers for the members of the aggregate, in increasing subscript or member order. Each
member is copy-initialized from the corresponding initializer-clause.

[dcl.init.list]/4 has:
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.

The copy-initialization of an aggregate member is certainly a side effect, but is it "associated with" the corresponding initializer-clause or is that only intended to cover side-effects like in S s{++i, ++i}?

The alternative would be that the copy-initialization of aggregate members is associated with the full-expression; this could e.g. be more efficient where it is possible to initialize multiple aggregate members en bloc.

Richard Smith

unread,
Feb 27, 2015, 2:58:03 PM2/27/15
to std-dis...@isocpp.org
5 and s.i are full-expressions here; there is no larger expression of which they are subexpressions. 

David Rodríguez Ibeas

unread,
Feb 27, 2015, 4:39:47 PM2/27/15
to std-dis...@isocpp.org
The question, I believe, is whether the initialization of s.i is sequenced before the evaluation of the second initializer. I personally don't think that is guaranteed, that is, for the expression:

struct S { int a, b; } s = { f(), g() };

The following would be two legal code generations:

// 1
auto __tmp1 = f();
auto __tmp2 = g();
S.a = __tmp1;
S.b = __tmp2;

// 2
S.a = f();
S.b = g();

If the first of these options is a legal translation of the initializer above, then the program presented would have undefined behavior, as the initializer for the second member uses an lvalue-to-rvalue conversion on a yet uninitialized value.

Without explicit requirements in the standard the sequencing constrains only guarantee that 'f()' is called before 'g()', but 'g()' is not sequenced before or after the initialization of 'S.a'.

Note that the sequencing constrains in 8.5.4/.4 include calls to constructors, where all of the initializers are sequenced before the constructor call. I don't see why a compiler would not be allowed to do the same for aggregate initialization (i.e. calculate all values, then store to the object).

--

---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussio...@isocpp.org.
To post to this group, send email to std-dis...@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-discussion/.

Richard Smith

unread,
Feb 27, 2015, 5:42:56 PM2/27/15
to std-dis...@isocpp.org
On Fri, Feb 27, 2015 at 1:39 PM, David Rodríguez Ibeas <dib...@ieee.org> wrote:
The question, I believe, is whether the initialization of s.i is sequenced before the evaluation of the second initializer.

We have:

[intro.execution]p10: "A full-expression is an expression that is not a subexpression of another expression. [...] If a language construct is defined to produce an implicit call of a function, a use of the language construct is considered to be an expression for the purposes of this definition."

Since a braced-init-list is not an expression, and in this case it does not result in a function call, 5 and s.i are separate full-expressions. Then:

[intro.execution]p14: "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."

So the only question is, is the side-effect of initializing s.i "associated with" the evaluation of the full-expression "5"? I think the only reasonable assumption is that it is: if 5 were initializing a member of class type, the constructor call would obviously be part of the full-expression by the definition in [intro.execution]p10, so it is natural to assume that the same is true for scalar types.

However, I don't think the standard actually explicitly says this anywhere.

Johannes Schaub

unread,
Feb 27, 2015, 7:35:52 PM2/27/15
to std-dis...@isocpp.org


Am 27.02.2015 23:42 schrieb "Richard Smith" <ric...@metafoo.co.uk>:
>
> On Fri, Feb 27, 2015 at 1:39 PM, David Rodríguez Ibeas <dib...@ieee.org> wrote:
>>
>> The question, I believe, is whether the initialization of s.i is sequenced before the evaluation of the second initializer.
>
>
> We have:
>
> [intro.execution]p10: "A full-expression is an expression that is not a subexpression of another expression. [...] If a language construct is defined to produce an implicit call of a function, a use of the language construct is considered to be an expression for the purposes of this definition."
>
> Since a braced-init-list is not an expression, and in this case it does not result in a function call, 5 and s.i are separate full-expressions. Then:
>
> [intro.execution]p14: "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."
>
> So the only question is, is the side-effect of initializing s.i "associated with" the evaluation of the full-expression "5"? I think the only reasonable assumption is that it is: if 5 were initializing a member of class type, the constructor call would obviously be part of the full-expression by the definition in [intro.execution]p10, so it is natural to assume that the same is true for scalar types.
>

I agree. See my answer in the other thread.

Reply all
Reply to author
Forward
0 new messages