Order of evaluation in initializer_list c++11 - c++

In the code below is it required that f1 be called before f2 (or vice-versa) or is it unspecified?
int f1();
int f2();
std::initializer_list<int> list { f1(), f2() };

This is one interesting corner of the C++ standard where execution order is well defined. Section 8.5.4 [dcl.init.list], paragraph 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. 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.
So in the initializer list, the function calls are evaluated left-to-right.

Related

Does the order of arguments while returning a pair/struct/tuple matter in following code?

In the following code, is the return value correctly created. I have some doubt as both the arguments to the pair constructor are related. Does the use of move for second argument corrupts the first argument. Or if the first argument is always created before the second argument:
class A
{
private:
struct B
{
int a;
string b;
int c;
};
struct C
{
double d;
float f;
};
struct Key
{
int a;
string b;
double d;
};
struct Data
{
B x;
C y;
};
public:
Data data;
using ReturnType = pair<Key, Data>;
ReturnType operator()(Source input)
{
// use input to fill Data
return {{data.x.a, data.x.b, data.y.d}, move(this->data)};
}
};
Note: Source may be database cursor, standard input stream, or may be a file pointer containing relevant data.
Does c++ standard define the order in which the pair will be created. Is there any difference between c++11 and c++17 regarding this.
From this evaluation order reference:
In list-initialization, every value computation and side effect of a given initializer clause is sequenced before every value computation and side effect associated with any initializer clause that follows it in the brace-enclosed comma-separated list of initalizers.
What it is saying is that in the expression
{{data.x.a, data.x.b, data.y.d}, move(this->data)}
the {data.x.a, data.x.b, data.y.d} part will be sequenced before (i.e. evaluated before) move(this->data).
n3337, The C++11 standard draft, contains this passage
[dcl.init.list]
4 Within the initializer-list of a braced-init-list, the
initializer-clauses, including any that result from pack expansions
([temp.variadic]), 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. [ Note: This
evaluation ordering holds regardless of the semantics of the
initialization; for example, it applies when the elements of the
initializer-list are interpreted as arguments of a constructor call,
even though ordinarily there are no sequencing constraints on the
arguments of a call. — end note ]
So when using brace initialization, the argument to initialize the Key in the ReturnType is going to be evaluated in full before the argument for the Data.
There is similar wording in every C++ standard since.

Argument evaluation order between curly braces and parentheses

#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
uint32_t func() { return rand() % 10; }
struct A {
uint32_t _x, _y, _z;
A(uint32_t x, uint32_t y, uint32_t z) : _x(x), _y(y), _z(z) {}
};
int main() {
A a{func(), func(), func()};
//A a(func(), func(), func());
printf("%d %d %d\n", a._x, a._y, a._z);
return 0;
}
GCC 9.1 and MSVC 19.22.27905 will both print a different order when using curly braces or parentheses.
Clang 8.0.0 will print the same order for both cases.
I can´t find anything in the standard about it, is it in the standard or is it up to the compiler which orders it evaluates the input argument?
The order is only guaranteed for braced-init-list, [dcl.init.list]/4:
(emphasis mine)
Within the initializer-list of a braced-init-list, the initializer-clauses, including any that result from pack expansions ([temp.variadic]), 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. [ Note: This evaluation ordering holds regardless of the semantics of the initialization; for example, it applies when the elements of the initializer-list are interpreted as arguments of a constructor call, even though ordinarily there are no sequencing constraints on the arguments of a call. — end note ]
On the other hand, order of evaluation of arguments in a function call is unspecified.
unspecified behavior - the behavior of the program varies between implementations and the conforming implementation is not required to document the effects of each behavior. For example, order of evaluation, whether identical string literals are distinct, the amount of array allocation overhead, etc. Each unspecified behavior results in one of a set of valid results.
It seems that Clang evaluates arguments in this declaration
A a( func(), func(), func() );
from left to right. While the other compilers evaluate them in the order from right to left.
The order of the evaluation of arguments is unspecified.
As for the curly braces then the evaluation is strictly determined from left to right and evaluation of each expression is sequenced.

Can I Reference Previous Members of an Initializer List?

Say I want to refer to a member of an initializer_list that I already defined. Can I do it?
This code compiles and gives the expected: "13 55 " in both Visual Studio and gcc, I'd just like to know that it's legal:
const int foo[2] = {13, foo[0] + 42};
So what we have here is aggregate initialization covered in section 8.5.1 of the draft C++ standard and it says:
An aggregate is an array or a class [...]
and:
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 [...]
Although it seems reasonable that side effects from initializing each member of the aggregate should be sequenced before the next, since each element in the initializer list is a full expression. The standard does not actually guarantee this we can see this from defect report 1343 which says:
The current wording does not indicate that initialization of a non-class object is a full-expression, but presumably should do so.
and also notes:
Aggregate initialization could also involve more than one full-expression, so the limitation above to “initialization of a non-class object” is not correct.
and we can see from a related std-discussion topic Richard Smith says:
[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.
So this is currently not specified by the standard and can not be relied upon, although I would be surprised if an implementation did not treat it the way you expect.
For a simple case like this something similar to this seems a better alternative:
constexpr int value = 13 ;
const int foo[2] = {value, value+42};
Changes In C++17
The proposal P0507R0: Core Issue 1343: Sequencing of non-class initialization clarifies the full-expression point brought up here but does not answer the question about whether the side-effect of initialization is included in the evaluation of the full-expression. So it does not change that this is unspecified.
The relevant changes for this question are in [intro.execution]:
A constituent expression is defined as follows:
(9.1) — The constituent expression of an expression is that expression.
(9.2) — The constituent expressions of a braced-init-list or of a (possibly parenthesized) expression-list are the
constituent expressions of the elements of the respective list.
(9.3) — The constituent expressions of a brace-or-equal-initializer of the form = initializer-clause are the
constituent expressions of the initializer-clause.
[ Example:
struct A { int x; };
struct B { int y; struct A a; };
B b = { 5, { 1+1 } };
The constituent expressions of the initializer used for the initialization of b are 5 and 1+1. —end example ]
and [intro.execution]p12:
A full-expression is
(12.1) — an unevaluated operand (Clause 8),
(12.2) — a constant-expression (8.20),
(12.3) — an init-declarator (Clause 11) or a mem-initializer (15.6.2), including the constituent expressions of the
initializer,
(12.4) — an invocation of a destructor generated at the end of the lifetime of an object other than a temporary
object (15.2), or
(12.5) — an expression that is not a subexpression of another expression and that is not otherwise part of a
full-expression.
So in this case both 13 and foo[0] + 42 are constituent expression which are part of a full-expression. This is a break from the analysis here which posited that they would each be their own full-expressions.
Changes In C++20
The Designated Initialization proposal: P0329 contains the following addition which seems to make this well defined:
Add a new paragraph to 11.6.1 [dcl.init.aggr]:
The initializations of the elements of the aggregate are evaluated in the element order. That is,
all value computations and side effects associated with a given element are sequenced before those of any element that follows it in order.
We can see this is reflected in the latest draft standard.

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

Order of operation when performing dynamic initialization of arrays

I skimmed through section dcl.init.aggr and couldn't find a clear answer.
Consider:
static int x[2] = { f(), g() };
Does the standard say which gets initalized first: x[0] or x[1] ?
In other words, which function runs first: f(), or g() ?
Here are some relevant excerpts from the standard that answer your question:
8.5.1/2 "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."
8.5.4/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. 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.
[ Note: This evaluation ordering holds regardless of the semantics of the initialization; for example, it applies when the elements of the initializer-list are interpreted as arguments of a constructor call, even though ordinarily there are no sequencing constraints on the arguments of a call. —end note ]
If I remember correctly the standard does not define the order of evaluation and it is implementation specific.