Topic: order of evaluation in aggregate initializers


Author: fvali@biotrack.com
Date: 1999/01/26
Raw View
In article <slrn7anej3.qo.sbnaran@dirac.ceg.uiuc.edu>,
  sbnaran@KILL.uiuc.edu wrote:
>
<snip>
>
> The order of evaluation should be well defined -- go from
> left to right.  This is because an array is basically a struct
> where the members have numerical names.  Now in a struct,
> it is well known that members are initialized in the order
> they are declared, and hence the initialization of the
> second variable can depend on the first variable.  (It is
> better style to avoid dependencies in the member initialization
> list as dependencies lead to code that is less maintainable.

I saw nothing in the standard that clearly defines and
requires this behavior.
Clause 8 defines default initialization, and zero intialization
but it never talks about sequence points during initialization
or the order of initialization (unless of course I missed it,
in which case I will be obliged if someone could point it out
to me), although it does define how initializers in
aggregate initializers correspond to their respective
members.

12.6, item 3 states that the constructor for an array of
_class_ objects is called
in their subscript order - but nothing is said about non-class objects
such as ints for example.


There is one section in clause 12 on Mem Initializers (12.6.2),
but I feel that most of its definitions pertain only to
class objects and mem-initializer-lists.

In 12.6.2:
Item 3 clearly states that there are sequence points
after initializing a base and a member, but before it states that
it prefaces the statements with : "The semantics of a mem-initializer
are as follows:"
So can we assume these sequence points always exist
during initialization of members?


Item 5 really spells things out for class objects (POD structs included
too of course) and defines the order of intialization as the order of
declaration of members which i guess makes this well-defined:

struct S
{
  int a, b, c
};

int a;
S s = { a, s.a++, s.b++ }; // If sequence points exist btw inits

But _nothing_ is said about arrays of scalar types.


> But it might be necessary at times).  For example,
>
> struct X
> {
>    private:
>       int a,b,c;
>    public:
>       explicit X(int a_) : a(a_), b(a+1), c(b+1) { }
> };
Yes, I agree the standard is very clear about the above behavior.


>
> The following line sets x.a==1, x.b==2, x.c==3.
>    X x(1);
>
> The array int[3] is conceptually equivalent to struct X.  In
> fact, int[0]==X::a, int[1]==X::b, int[2]==X::c.  Therefore
>    int x[3]={1,x[0]+1,x[1]+1};
> sould have the same effect.

Is there anything in the standard that we can use to validate
the above statement?

>
> Consider this program.
>
> ----------------------------------------------
>
> #include <iostream.h>
>
> int main()
> {
>    int x[3]={1,x[0]+1,x[1]+1};
>    cout << x[0] << ' ' << x[1] << ' ' << x[2] << '\n';
> }
>
> ----------------------------------------------
>
> The result should be "1 2 3".
> But egcs gives me "1 1073782129 2" which is not what I expect.
> So maybe my reasoning is wrong :).
>
<snip disclaimer and response>

> >int a;
> >
> >int f1() { return ++a; }
> >int f2() { return ++a; }
> >int f3() { return ++a; }
>
> OK.  Note that static, global, and namespace variables are
> initialized to zero.  So 'a' is initialized to zero.
True, all objects of static storage duration are zero-initialized.
But, I'd like to add a few things, and please do check me on them.

'a' is zero because it has no initializer, and its state is
never modified after its zero-initialization.

Had we defined globally
int b = 7;
b would first be zero-initialized and _then_ statically initialized
to 7 before any other objects are dynamically initialized.

Had we defined a local static object, it would also be
zero-initialized before any other initialization occured.

If our static local object was a POD type initialized by
a constant expression its initialization would occur
just _before_ the block is first entered.

>
> >int trouble()
> >{
> >  int arr[] = { f1(), f2(), f3() };
> >  // What guarantees can be made about the above statement?
> >  // Can we say that f1 will be called before f2 which
> >  // will be called before f3 (ignoring the as-if rule)
> >
> >  int arr2[] = { ++a, ++a, ++a };
> >  // The above statement introduces undefined behavior, right?
> >  // Since there are no inherent sequence points between initializers
> >  // in an aggregate initializer list.
> >
> >
> >}
>
> The rules for "arr" and "arr1" must be the same because f1()
> is equivalent to "++a" (after inlining), and f2() is equivalent
> to "++a" as well, as is f3().
By that rationale couldn't we say that this is well-defined:

inline int modify(int& x_i) { return ++x_i; }

int a = modify( a ); //well-defined, I think

Even though 'modify' is inlined the rules for this are not the same:

int a = a++; //undefined, definitely


>
> Anyway, I say that arr should be {1,2,3} although egcs probably
> disagrees with me.
I think arr _should_ be 1,2,3 too, but where in the
standard is this behavior clearly defined.
And I think arr2 should be well defined too, but once
again i can't find anything in the standard to validate
this.
If this behavior is not well-defined in the standard,
I feel it should be.
-fais

-----------== Posted via Deja News, The Discussion Network ==----------
http://www.dejanews.com/       Search, Read, Discuss, or Start Your Own
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: sbnaran@dirac.ceg.uiuc.edu (Siemel Naran)
Date: 1999/01/25
Raw View
On 24 Jan 1999 00:25:04 GMT, fvali@biotrack.com <fvali@biotrack.com> wrote:

>Now I know that the order of evaluation of arguments
>to a function is unspecified, and that there are no
>inherent sequence points (though they can be introduced)
>between evaluation of arguments, but what about
>order of evaluation of initializers in
>aggregate initializer lists.

The order of evaluation should be well defined -- go from
left to right.  This is because an array is basically a struct
where the members have numerical names.  Now in a struct,
it is well known that members are initialized in the order
they are declared, and hence the initialization of the
second variable can depend on the first variable.  (It is
better style to avoid dependencies in the member initialization
list as dependencies lead to code that is less maintainable.
But it might be necessary at times).  For example,

struct X
{
   private:
      int a,b,c;
   public:
      explicit X(int a_) : a(a_), b(a+1), c(b+1) { }
};


The following line sets x.a==1, x.b==2, x.c==3.
   X x(1);

The array int[3] is conceptually equivalent to struct X.  In
fact, int[0]==X::a, int[1]==X::b, int[2]==X::c.  Therefore
   int x[3]={1,x[0]+1,x[1]+1};
sould have the same effect.

Consider this program.


----------------------------------------------


#include <iostream.h>

int main()
{
   int x[3]={1,x[0]+1,x[1]+1};
   cout << x[0] << ' ' << x[1] << ' ' << x[2] << '\n';
}

----------------------------------------------

The result should be "1 2 3".
But egcs gives me "1 1073782129 2" which is not what I expect.
So maybe my reasoning is wrong :).



>Disclaimer: I do not endorse these techniques or style of
>coding, but i use them here because they allow me to present
>simple and clear examples that succintly embody the
>concepts I am trying to have clarified.

OK.


>int a;
>
>int f1() { return ++a; }
>int f2() { return ++a; }
>int f3() { return ++a; }

OK.  Note that static, global, and namespace variables are
initialized to zero.  So 'a' is initialized to zero.


>int trouble()
>{
>  int arr[] = { f1(), f2(), f3() };
>  // What guarantees can be made about the above statement?
>  // Can we say that f1 will be called before f2 which
>  // will be called before f3 (ignoring the as-if rule)
>
>  int arr2[] = { ++a, ++a, ++a };
>  // The above statement introduces undefined behavior, right?
>  // Since there are no inherent sequence points between initializers
>  // in an aggregate initializer list.
>
>
>}

The rules for "arr" and "arr1" must be the same because f1()
is equivalent to "++a" (after inlining), and f2() is equivalent
to "++a" as well, as is f3().

Anyway, I say that arr should be {1,2,3} although egcs probably
disagrees with me.


--
----------------------------------
Siemel B. Naran (sbnaran@uiuc.edu)
----------------------------------


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: fvali@biotrack.com
Date: 1999/01/24
Raw View


Now I know that the order of evaluation of arguments
to a function is unspecified, and that there are no
inherent sequence points (though they can be introduced)
between evaluation of arguments, but what about
order of evaluation of initializers in
aggregate initializer lists.

For e.g. consider the following fragments of code:


Disclaimer: I do not endorse these techniques or style of
coding, but i use them here because they allow me to present
simple and clear examples that succintly embody the
concepts I am trying to have clarified.

int a;

int f1() { return ++a; }
int f2() { return ++a; }
int f3() { return ++a; }

int trouble()
{
  int arr[] = { f1(), f2(), f3() };
  // What guarantees can be made about the above statement?
  // Can we say that f1 will be called before f2 which
  // will be called before f3 (ignoring the as-if rule)

  int arr2[] = { ++a, ++a, ++a };
  // The above statement introduces undefined behavior, right?
  // Since there are no inherent sequence points between initializers
  // in an aggregate initializer list.


}


Thanks in advance.
-fais






-----------== Posted via Deja News, The Discussion Network ==----------
http://www.dejanews.com/       Search, Read, Discuss, or Start Your Own


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]