Is (1) undefined behavior, or is the first element of the pair always evaluated first?
#include <array>
#include <utility>
int bar(std::array<int, 3>&& ) {
return 1;
}
std::pair<std::array<int, 3>, int> foo() {
std::array<int, 3> a;
return { a, bar(std::move(a)) }; // (1)
}
As a side note, would using return make_pair(a, bar(std::move(a))); instead be different?
You might see the rule of evaluation order.
10) 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 initializers.
So for
return { a, bar(std::move(a)) };
a is firstly evaluated, then bar(std::move(a)).
As a side note, would using return make_pair(a, bar(std::move(a))); instead be different?
Yes, this is a function call, and order of evaluation is unspecified. it is not UB by itself, but can lead to UB if one order lead to UB.
In your case both orders are fine and give same result.
C++17 adds that restriction moreover:
15) In a function call, value computations and side effects of the initialization of every parameter are indeterminately sequenced with respect to value computations and side effects of any other parameter.
Related
#include <string>
struct X
{
char y;
std::string z;
X & operator()(std::string && s)
{
z = std::move(s);
return *this;
}
X & operator()(char c)
{
y = c;
return *this;
}
};
int main()
{
X x;
std::string y("abc");
x(y[0])(std::move(y));
}
is the last line of main undefined behavior? I'm guessing yes because it would unfold to something like the following but just want to make sure that there are no stricter guarantees on call operators or member function invocations in general
X::operator()(&X::operator()(&x, y[0]), std::move(z))
Please add references from the standard or cppref
Before c++17, chaining function calls that modify the same l-value, like in your example, is indeed undefined behavior, since the order of evaluation of these expressions is unspecified.
However, a proposal to fix that was merged into c++17.
Here's the relevant rule (emphasis mine), which also contains an example from the proposal that shows how this works:
The postfix-expression is sequenced before each expression in the expression-list and any default argument. The initialization of a parameter, including every associated value computation and side effect, is indeterminately sequenced with respect to that of any other parameter. [Note: All side effects of argument evaluations are sequenced before the function is entered (see [intro.execution]). — end note] [Example:
void f() {
std::string s = "but I have heard it works even if you don't believe in it";
s.replace(0, 4, "").replace(s.find("even"), 4, "only").replace(s.find(" don't"), 6, "");
assert(s == "I have heard it works only if you believe in it"); // OK
}
— end example]
While the above rule only strictly refers to the built-in operator(), and you have user-defined operators, the same rules about order of evaluation apply, because of this rule:
If either operand has a type that is a class or an enumeration, a user-defined operator function might be declared that implements this operator or a user-defined conversion can be necessary to convert the operand to a type that is appropriate for a built-in operator. ... However, the operands are sequenced in the order prescribed for the built-in operator.
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.
Consider the following program (and its alternative in the comment) in C++17:
#include<iostream>
void a(int) {
std::cout << "a\n";
}
void b(int) {
std::cout << "b\n";
}
int main() {
using T = void(*)(int);
T f = a;
(T(f))((f=b,0)); // alternatively: f((f=b,0))
}
With -O2 option, Clang 9.0.0 prints a and GCC 9.2 prints b. Both warn me about unsequenced modification and access to f. See godbolt.org.
My expectation was that this is program has well-defined behavior and will print a, because C++17 guarantees that the left-hand expression of the call (T(f)) is sequenced before any evaluation of the arguments. Because the result of the expression (T(f)) is a new pointer to a, the later modification of f should have no impact on the call at all. Am I wrong?
Both compilers give the same output if I use f((f=b,0)); instead of (T(f))((f=b,0));. Here I am slightly unsure about the undefined behavior aspect. Would this be undefined behavior because f still refers to the declared function pointer after evaluation, which will have been modified by the evaluation of the arguments and if so, why exactly would that cause undefined behavior rather than calling b?
I have asked a related question with regards to order of evaluation of non-static member function calls in C++17 here. I am aware that writing code like this is dangerous and unnecessary, but I want to understand the details of the C++ standard better.
Edit: GCC trunk now also prints a after the bug filed by Barry (see his answer below) has been fixed. Both Clang and GCC trunk do still show false-positive warnings with -Wall, though.
The C++17 rule is, from [expr.call]/8:
The postfix-expression is sequenced before each expression in the expression-list and any default argument. The initialization of a parameter, including every associated value computation and side effect, is indeterminately sequenced with respect to that of any other parameter.
In (T(f))((f=b,0));, (T(f)) is sequenced before the initialization of the parameter from (f=b, 0). All of this is well-defined and the program should print "a". That is, it should behave just like:
auto __tmp = T(f);
__tmp((f=b, 0));
The same is true even if we change your program such that this were valid:
T{f}(f=b, 0); // two parameters now, instead of one
The f=b and 0 expressions are indeterminately sequenced with each other, but T{f} is still sequenced before both, so this would still invoke a.
Filed 91974.
#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.
I suspect the following chaining of functions would result in unspecified sequence according to the C++ standards (assume C++0x). Just want a confirmation and if anyone could provide an explanation, I'd appreciate it.
#include <iostream>
struct TFoo
{
TFoo(int)
{
std::cout<<"TFoo"<<std::endl;
};
TFoo foobar1(int)
{
std::cout<<"foobar1"<<std::endl;
return *this;
};
TFoo foobar2(int)
{
std::cout<<"foobar2"<<std::endl;
return *this;
};
static int bar1()
{
std::cout<<"bar1"<<std::endl;
return 0;
};
static int bar2()
{
std::cout<<"bar2"<<std::endl;
return 0;
};
static int bar3()
{
std::cout<<"bar3"<<std::endl;
return 0;
}
};
int main(int argc, char *argv[])
{
// is the sequence well defined for bar1, bar2 and bar3?
TFoo(TFoo::bar1()).foobar1(TFoo::bar2()).foobar2(TFoo::bar3());
}
* edit: removed __fastcall specifier for functions (not required/relevant to the question).
The evaluation order is not specified. The relevant section of the draft C++0x spec is 1.9, paragraphs 14 and 15:
14 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.
15 Except where noted, evaluations of operands of individual operators and of subexpressions of individual expressions are unsequenced.
Here the relevant full-expression is:
TFoo(TFoo::bar1()).foobar1(TFoo::bar2()).foobar2(TFoo::bar3());
And so the evaluation of its subexpressions are unsequenced (unless there is an exception noted somewhere that I missed).
I am pretty sure earlier standards include language having the same effect but in terms of "sequence points".
[edit]
Paragraph 15 also says:
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. [Note: Value computations and side effects associated with different argument expressions are unsequenced.— end note]
A "postfix expression designating the called function" is something like the foo().bar in foo().bar().
The "note" here merely clarifies that argument evaluation order is not an exception to the "unspecified order" default. By inference, neither is the evaluation order associated with the "postfix expression designating the called function"; or if you prefer, the evaluation order of the expression for the this argument. (If there were an exception, this would be the natural place to specify it. Or possibly section 5.2.2 that talks about function calls. Neither section says anything about the evaluation order for this example, so it is unspecified.)
Yes, the order of evaluation of function arguments is unspecified.
For me, gcc 4.5.2 on linux produces
bar3
bar2
bar1
TFoo
foobar1
foobar2
but clang++ on linux and gcc 3.4.6 on solaris produce
bar1
TFoo
bar2
foobar1
bar3
foobar2
To analyze a simpler example, TFoo(0).foobar1(TFoo::bar2()); is a call to TFoo::foobar1 which takes two arguments: the result of the subexpression TFoo(0) (as the hidden argument this) and the result of the subexpression Tfoo::bar2(). For me, gcc executs bar2() first, then TFoo's constructor, and then calls foobar1(), while clang++ for example, executes TFoo's constructor first, then bar2() and then calls foobar1().