Sequence points in aggregate initialization.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <iostream>

using namespace std;

struct aggregate {
    int i;
    int j;
};

int main (void)
{
    aggregate s = {5, s.i};

    cout << s.i << ' ' << s.j //outputs "5 5"
         << endl;
}


The following code outputs "5 5" when compiled with gcc. Is this behavior standard or is it implementation defined?

I know there are sequence points after each initializer in member initialization lists of constructors and consequently every following initialization can refer to members already initialized (i.e. with predictable results).

Does this also apply to aggregate intializers?

Thanks
No, it does not. The comma (,) in an aggregate initializer is not a sequence point.
There is no reason for it to be. You don't know anything more or less at any point during the aggregate initialization.

Hope this helps.
I thought so. The standard does not discuss side-effects during aggregate initialization specifically (I think), so I assumed implementation behavior myself, but I had to ask.

Thanks.
Last edited on
However, an aggregate initializer has to initialize members in the order of declaration since there is otherwise no way
for the compiler to know which member gets initialized with what value. Eg,

 
aggregate s = { 5, 6 };


The compiler has to have some kind of standard that defines which member -- i or j -- gets the value 5 and which gets 6.
In this case, values are assigned in the order of declaration. That said, the original program is well-defined.

Note that the example above is essentially the same as:

1
2
3
4
struct aggregate {
    /* explicit */ aggregate( int x ) : i( x ), j( i ) {}
    int i, j;
};


which is also well-defined. This technique is used in various places in the boost libraries.
jsmith wrote:
Note that the example above is essentially the same as...
Ok, I am opening the question again, just to be clear on the subject.

jsmith, I didn't find explicit statement of the semantic equivalence you mention. Its not like I read the whole standard though. I only skim the seemingly relevant sections on a per need basis.

Do we know this for sure, or is it deducible? Can I read this in some section from the standard, comment from Stroustrap, or in some literature? It counts for me, as long as the source is "officially" recognized as supplementary reference. No need to quote, just please say why you think so.

Thanks and Regards
Last edited on
Let me look at the standard a bit to try to find it.
What about array initialization?

1
2
char s[7] = {'a', s[0], s[1], s[2], s[3], s[4], 0};
cout << s << endl;


This outputs the same thing on all my compilers (g++, Sun Studio, clang++): a string of "a"s.
aggregate( int x ) : i( x ), j( i )

My understanding was that you couldn't do this either...maybe I'm wrong though?
@firedraco: that is definitely legal.
I looked at the an older draft of the C++0x standard, and here's what I found.

8.5.1 Aggreates [dcl.init.aggr]

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

This outputs the same thing on all my compilers

Sorry for the delay. Thanks a lot for the research. Then the compiler vendors are consistent. But IMO it is not yet standard. It appears to be common fact, so thanks for the info.

Recently my attention was drawn to some upcoming standard ratification - string c_str function will have constant time complexity. Apparently, that must have been a fact already for many major compiler brands or easy to implement. The thing had to be simply taken to the next level, but as it stands now, the behavior of aggregate initializers is IMO implementation defined.

On the other hand, I can never discriminate - what is underspecified and what is intently specified as undefined. The statements are not given any formal expression, so they can not be formally analyzed and formal inference is not applicable. You can never prove that some statement is specified or not, because only the direct applications have clear interpretation. Once you start picking on not-so-mainstream topics and you are in the dark.

To this day, I am still puzzled regarding pointer comparison issues and such. I don't want to delve further on this subject here. May be I'll create a thread with pointer questions again some day :)
(I am stubborn and persistent.)

I can not resist polluting this topic a bit though: when you interpret the standard (or drafts of it like me), do you ever rely on inferences of facts that were not obviously intent? Figuratively speaking - do you rely on stuff that comes from the side-pocket of some rule, or you look for clearly intent consequences only?

Thanks a bunch to everyone

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

Yeah, I think I saw that myself, but it settles another question - the order in which side-effects from the expressions will be applied. (Not these side-effects we are discussing...) It may have been the intention to mean more then that, but IMO this exact wording does not carry the message that my code is portable.
Last edited on
(Sorry, I should have mentioned that although I looked at the draft standard, I'm sure this is text carried over from the previous, meaning that it would currently be standard).

However, I agree that it does not explicitly answer your question, however I think it must be ok, as I can't imagine a compiler doing it any other way.
I know what you mean. Again, I really appreciate the effort. My conclusions are this: good portability in practice, possible issues in theory.
Topic archived. No new replies allowed.