C++ Expression evaluation. What does 'evaluation' mean? - c++

I understand the problems with the classic example of
int i=0;
foo(i++, i++);
but I can't convince myself of whether the following is valid or invalid
int foo(int& i)
{
i=42;
return 99;
}
bar(foo(i), i);
I understand that the order 'foo(i)' and 'i' are evaluated is undefined, but what exactly does 'evaluated' mean? i.e. will the 2nd parameter of bar always be 42, or can the current value of 'i' be passed in before foo changes it?

No it is not guaranteed.
The order of evaluation of arguments to an function is Unspecified[Ref 1].
It can be possible that either:
foo(i) gets evaluated first or
i gets evaluated or
any other magical order(in case number of arguments were more than two)
Unspecified in this context means the implementation is allowed to implement the said feature whichever way they want and it need not be documented.
[Ref 1]
C++03 5.2.2 Function call
Para 8
The order of evaluation of arguments is unspecified. All side effects of argument expression evaluations take effect before the function is entered. The order of evaluation of the postfix expression and the argument expression list is unspecified.

This sample (gcc 4.6)
#include <iostream>
using namespace std;
int foo(int& i)
{
i=42;
return 99;
}
void bar(int i, int j)
{
cout << "i = " << i << "; j = " << j << endl;
}
int main()
{
int i =10;
bar(foo(i), i);
return 0;
}
gives i = 99, j = 10.
So it is really not guaranteed.

Related

Are function arguments not evaluated left to right? How are side effects on the same variable ordered?

Consider the following program.
#include<iostream>
using namespace std;
void fn(int a, int b)
{
cout << a;
cout << b;
}
int main()
{
int a = 10;
fn(a++, --a);
fn(a--, ++a);
return 0;
}
I don't understand the output I get (gcc 11.2):
9101110
Shouldn't a++ be evaluated first? How can fn then get a 9? Is this undefined behavior or simply "indeterminate"? Did C++17 change in this respect?
This is undefined behavior. The order of parameter evaluation is unspecified.
See here.
So this question is irrelevant and code like this should never be used.
The output can be 9 10 11 10 on one compiler, and a totally different value on another compiler (while both compilers remain standard-complaint).

Static variable in C++ value is not getting updated even when incrementing in function [duplicate]

Hi all I stumbled upon this piece of code today and I am confused as to what exactly happens and more particular in what order :
Code :
#include <iostream>
bool foo(double & m)
{
m = 1.0;
return true;
}
int main()
{
double test = 0.0;
std::cout << "Value of test is : \t" << test << "\tReturn value of function is : " << foo(test) << "\tValue of test : " << test << std::endl;
return 0;
}
The output is :
Value of test is : 1 Return value of function is : 1 Value of test : 0
Seeing this I would assume that somehow the right most argument is printed before the call to the function. So this is right to left evaluation?? During debugging though it seems that the function is called prior to the output which is what I would expect. I am using Win7 and MSVS 2010. Any help is appreciated!
The evaluation order of elements in an expression is unspecified (except some very particular cases, such as the && and || operators and the ternary operator, which introduce sequence points); so, it's not guaranteed that test will be evaluated before or after foo(test) (which modifies it).
If your code relies on a particular order of evaluation the simplest method to obtain it is to split your expression in several separated statements.
The answer to this question changed in C++17.
Evaluation of overloaded operators are now sequenced in the same way as for built-in operators (C++17 [over.match.oper]/2).
Furthermore, the <<, >> and subscripting operators now have the left operand sequenced before the right, and the postfix-expression of a function call is sequenced before evaluation of the arguments.
(The other binary operators retain their previous sequencing, e.g. + is still unsequenced).
So the code in the question must now output Value of test is : 0 Return value of function is : 1 Value of test : 1. But the advice "Don't do this" is still reasonable, given that it will take some time for everybody to update to C++17.
Order of evaluation is unspecified. It is not left-to-right, right-to-left, or anything else.
Don't do this.
The order of evaluation is unspecified, see http://en.wikipedia.org/wiki/Sequence_point
This is the same situation as the example with the operator+ example:
Consider two functions f() and g(). In C and C++, the + operator is not associated with a sequence point, and therefore in the expression f()+g() it is possible that either f() or g() will be executed first.
the c++ reference explains very well why that should never be done (is causing an UB or undefined behaviour)
https://en.cppreference.com/w/cpp/language/operator_incdec
#include <iostream>
int main()
{
int n1 = 1;
int n2 = ++n1;
int n3 = ++ ++n1;
int n4 = n1++;
// int n5 = n1++ ++; // error
// int n6 = n1 + ++n1; // undefined behavior
std::cout << "n1 = " << n1 << '\n'
<< "n2 = " << n2 << '\n'
<< "n3 = " << n3 << '\n'
<< "n4 = " << n4 << '\n';
}
Notes
Because of the side-effects involved, built-in increment and decrement
operators must be used with care to avoid undefined behavior due to
violations of sequencing rules.
and in the section related to sequencing rules you can read the following:
Undefined behavior:
1) If a side effect on a scalar object is unsequenced relative to another side effect on the same scalar object, the behavior is undefined.
i = ++i + 2; // undefined behavior until C++11
i = i++ + 2; // undefined behavior until C++17
f(i = -2, i = -2); // undefined behavior until C++17
f(++i, ++i); // undefined behavior until C++17, unspecified after C++17
i = ++i + i++; // undefined behavior
2) If a side effect on a scalar object is unsequenced relative to a value computation using the value of the same scalar object, the behavior is undefined.
cout << i << i++; // undefined behavior until C++17
a[i] = i++; // undefined behavior until C++17
n = ++i + i; // undefined behavior

C++ postfix expression undefined vs unspecified behaviour

Apologies in advance, I know the general topic of evaluation order has had a lot of SO questions on it already. However, having looked at them, I want to clarify a few specific points that I don't think amount to a duplication of anything. Suppose I have the following code:
#include <iostream>
auto myLambda(int& n)
{
++n;
return [](int param) { std::cout << "param: " << param << std::endl; };
}
int main()
{
int n{0};
myLambda(n)(n);
return 0;
}
The program above outputs "n: 0" when I compile it. Here we have unspecified ordering at play: it could have just as easily output "n: 1" had a different evaluation order taken place.
My questions are:
What exactly is the sequencing relationship at play during the final function invocation above (i.e. the lambda-expression invocation), between the postfix expression myLambda(0), its argument n, and the subsequent function call itself?
Is the above an example of undefined or unspecified behaviour - and why exactly (with reference to the standard)?
If I changed the lambda code to [](int param) { std::cout << "hello" << std::endl } (i.e. made the outcome independent of its parameter and thus any evaluation order decisions, making behaviour deterministic) would the answer to 2) above still be the same?
EDIT: I've change the lambda parameter name from 'n' to 'param' because that seemed to be causing confusion.
Ironically (since the example uses C++11 features, and other answers have been distracted by that) the logic that makes this sample have unspecified behaviour dates back to C++98, Section 5, para 4
Except where noted, the order of evaluation of operands of individual operators and subexpressions of individual expressions, and the order in which side effects take place, is unspecified. Between the previous and next sequence point a scalar object shall have its stored value modified at most once by the evaluation of an expression. Furthermore, the prior value shall be accessed only to determine the value to be stored. The requirements of this paragraph shall be met for each allowable ordering of the subexpressions of a full expression; otherwise the behavior is undefined.
Essentially the same clause exists in all C++ standards although, as noted in comment by Marc van Leeuwen, recent C++ standards no longer use the concept of sequence points. The net effect is the same: within a statement, the order or evaluation of operands of operators and subexpressions of individual expressions remains unspecified.
The unspecified behaviour occurs because an expression n is evaluated twice in the statement
myLambda(n)(n);
One evaluation of the expression n (to obtain a reference) is associated with the first (n) and another evaluation of an expression n (to obtain a value) is associated with the second (n). The order of evaluation of those two expressions (even though they are, optically, both n) is unspecified.
Similar clauses exist in ALL C++ standards, and have the same result - unspecified behaviour on the statement myLambda(n)(n), regardless of how myLambda() implemented
For example, myLambda() could be implemented in C++98 (and all later C++ standards, including C++11 and later) like this
class functor
{
functor() {};
int operator()(int n) { std::cout << "n: " << n << std::endl; };
};
functor myLambda(int &n)
{
++n;
return functor();
}
int main()
{
int n = 0;
myLambda(n)(n);
return 0;
}
since the code in the question is just a (C++11) technique (or shorthand) for achieving the same effect as this.
The above answers OP's questions 1. and 2. The unspecified behaviour occurs in main(), is unrelated to how myLambda() itself is implemented.
To answer the OP's third question, the behaviour is still unspecified if the lambda (or the functor's operator()) in my example) is modified to not access the value of its argument. The only difference is that the program as a whole produces no visible output that might vary between compilers.
The n in the definition of the lambda is a formal argument to the function that the lambda defines. It has no connection to the argument to myLambda that's also named n. The behavior here is dictated entirely by the way these two functions are called. In myLambda(n)(n) the order of evaluation of the two function arguments is unspecified. The lambda can be called with an argument of 0 or 1, depending in the compiler.
If the lambda had been defined with [=n]()... it would behave differently.
I didn't manage to find proper reference to standard but I see that it has similar behavior to argument evaluation order asked here and the order of function arguments evaluation is not defined by the standard:
5.2.2 Function call
8 [ Note: The evaluations of the postfix expression and of the argument expressions are all unsequenced relative to one another. All side effects of argument expression evaluations are sequenced before the function
is entered (see 1.9). —end note ]
So here's how it goes inside the calls on different compilers:
#include <iostream>
#include <functional>
struct Int
{
Int() { std::cout << "Int(): " << v << std::endl; }
Int(const Int& o) { v = o.v; std::cout << "Int(const Int&): " << v << std::endl; }
Int(int o) { v = o; std::cout << "Int(int): " << v << std::endl; }
~Int() { std::cout << "~Int(): " << v << std::endl; }
Int& operator=(const Int& o) { v = o.v; std::cout << "operator= " << v << std::endl; return *this; }
int v;
};
namespace std
{
template<>
Int&& forward<Int>(Int& a) noexcept
{
std::cout << "Int&: " << a.v << std::endl;
return static_cast<Int&&>(a);
}
template<>
Int&& forward<Int>(Int&& a) noexcept
{
std::cout << "Int&&: " << a.v << std::endl;
return static_cast<Int&&>(a);
}
}
std::function<void(Int)> myLambda(Int& n)
{
std::cout << "++n: " << n.v << std::endl;
++n.v;
return [&](Int m) {
std::cout << "n: " << m.v << std::endl;
};
}
int main()
{
Int n(0);
myLambda(n)(n);
return 0;
}
GCC g++ -std=c++14 -O2 -Wall -pedantic -pthread main.cpp && ./a.out and MSVC
Int(int): 0
Int(const Int&): 0
++n: 0
Int&: 0
Int&: 0
Int(const Int&): 0
n: 0
~Int(): 0
~Int(): 0
~Int(): 1
So it creates variable and copies it to pass to returned lamba.
Clang clang++ -std=c++14 main.cpp && ./a.out
Int(int): 0
++n: 0
Int(const Int&): 1
Int&: 1
Int&: 1
Int(const Int&): 1
n: 1
~Int(): 1
~Int(): 1
~Int(): 1
Here it creates variable evaluates function and then passees copy the lamba.
And the order of evaluation is:
struct A
{
A(int) { std::cout << "1" << std::endl; }
~A() { std::cout << "-1" << std::endl; }
};
struct B
{
B(double) { std::cout << "2" << std::endl; }
~B() { std::cout << "-2" << std::endl; }
};
void f(A, B) { }
int main()
{
f(4, 5.);
}
MSVC and GCC:
2
1
-1
-2
Clang:
1
2
-2
-1
As in clang order is forward and the argument to lambda is passed after evaluation of the function's argument
Ṫhe behaviour is unspecified, because in the function call (myLambda(n))(n) the postfix expression (which I gave an extra redundant pair of parentheses) is unsequenced relative to the argument expression n (the rightmost one). However there is no undefined behaviour, because the modification of n takes place inside the function call myLambda(n). The only definite sequencing relation is that both evaluating myLambda(n) and the final n are obviously sequenced before the actual call of the lambda. For the final question, is the lambda chooses to completely ignore its argument, then the behaviour is no longer unspecified: though it is unspecified what value gets passed as parameter, there is no observable difference either way.
The order in which sub expressions are evaluated is unspecified and can vary apart from the operators &&, ||,? and ",".
The compiler knows both function prototyps myLambda and also the return lambda(extracted from the return type). Cause my first sentence the compiler is free which expression he evaluates first. Thats why you should never call to functions in on expression which have additional side effects.

Can C++ constexpr function actually accept non-constant expression as argument?

I have defined a constexpr function as following:
constexpr int foo(int i)
{
return i*2;
}
And this is what in the main function:
int main()
{
int i = 2;
cout << foo(i) << endl;
int arr[foo(i)];
for (int j = 0; j < foo(i); j++)
arr[j] = j;
for (int j = 0; j < foo(i); j++)
cout << arr[j] << " ";
cout << endl;
return 0;
}
The program was compiled under OS X 10.8 with command clang++. I was surprised that the compiler did not produce any error message about foo(i) not being a constant expression, and the compiled program actually worked fine. Why?
The definition of constexpr functions in C++ is such that the function is guaranteed to be able to produce a constant expression when called such that only constant expressions are used in the evaluation. Whether the evaluation happens during compile-time or at run-time if the result isn't use in a constexpr isn't specified, though (see also this answer). When passing non-constant expressions to a constexpr you may not get a constant expression.
Your above code should, however, not compile because i is not a constant expression which is clearly used by foo() to produce a result and it is then used as an array dimension. It seems clang implements C-style variable length arrays as it produces the following warning for me:
warning: variable length arrays are a C99 feature [-Wvla-extension]
A better test to see if something is, indeed, a constant expression is to use it to initialize the value of a constexpr, e.g.:
constexpr int j = foo(i);
I used the code at the top (with "using namespace std;" added in) and had no errors when compiling using "g++ -std=c++11 code.cc" (see below for a references that qualifies this code) Here is the code and output:
#include <iostream>
using namespace std;
constexpr int foo(int i)
{
return i*2;
}
int main()
{
int i = 2;
cout << foo(i) << endl;
int arr[foo(i)];
for (int j = 0; j < foo(i); j++)
arr[j] = j;
for (int j = 0; j < foo(i); j++)
cout << arr[j] << " ";
cout << endl;
return 0;
}
output:
4
0 1 2 3
Now consider reference https://msdn.microsoft.com/en-us/library/dn956974.aspx It states: "...A constexpr function is one whose return value can be computed at compile when consuming code requires it. A constexpr function must accept and return only literal types. When its arguments are constexpr values, and consuming code requires the return value at compile time, for example to initialize a constexpr variable or provide a non-type template argument, it produces a compile-time constant. When called with non-constexpr arguments, or when its value is not required at compile-time, it produces a value at run time like a regular function. (This dual behavior saves you from having to write constexpr and non-constexpr versions of the same function.)"
It gives as valid example:
constexpr float exp(float x, int n)
{
return n == 0 ? 1 :
n % 2 == 0 ? exp(x * x, n / 2) :
exp(x * x, (n - 1) / 2) * x;
}
This is an old question, but it's the first result on a google search for the VS error message "constexpr function return is non-constant". And while it doesn't help my situation, I thought I'd put my two cents in...
While Dietmar gives a good explanation of constexpr, and although the error should be caught straight away (as it is with the -pedantic flag) - this code looks like its suffering from some compiler optimization.
The value i is being set to 2, and for the duration of the program i never changes. The compiler probably noticed this and optimized the variable to be a constant (just replacing all references to variable i to the constant 2... before applying that parameter to the function), thus creating a constexpr call to foo().
I bet if you looked at the disassembly you'd see that calls to foo(i) were replaced with the constant value 4 - since that is the only possible return value for a call to this function during execution of the program.
Using the -pedantic flag forces the compiler to analyze the program from the strictest point of view (probably done before any optimizations) and thus catches the error.

Order of evaluation example

I'm trying to set in my mind once and for all how expressions are being evaluated. And with this quest of mine I came up with this example which I don't know what to make of.
#include <iostream>
using namespace std;
typedef void(*func)(int);
void r( int i )
{
cout << i << endl;
}
func f( int i )
{
cout << i << endl;
return &r;
}
int main()
{
int i = 0;
f(++i)(++i);
return 0;
}
Having this piece of code compiled with MVSC 2008 will produce this output: 2 2. The same code but compiled with gcc 4.8.1 will raise an warning(operation on i may be undefined) and will produce this output: 1 2.
What I'm trying to understand is why gcc 4.8.1 considers that there might be a case of undefined behavior? The side-effects of both pre-increments are sequenced relative to each other.
Cheers,
Andrei
The side-effects of both pre-increments are sequenced relative to each other.
No they're not. Each argument evaluation is sequenced before its function call, and the function calls are sequenced with each other; but both could be evaluated before the first call, in which case there's nothing to sequence them with each other.
it depends on what you mean by 'pre-increment'... you are reading it like this:
++i
f(i)
++i
f (i) (i)
But you could just as easily do this:
++i
++i
f(i)
f(i) (i)
I don't think the specification requires one way or the other.