C++, ternary operator operand evaluation rules - c++

Lets say i have following code:
std::vector<T> R;
if (condition) R = generate();
...
for (int i = 0; i < N; ++i) {
const auto &r = (R.empty() ? generate() : R);
}
It appears that generate is called regardless of R.empty(). Is that standard behavior?

From Paragraph 5.16/1 of the C++ 11 Standard:
Conditional expressions group right-to-left. The first expression is contextually converted to bool (Clause 4). It is evaluated and if it is true, the result of the conditional expression is the value of the second expression, otherwise that of the third expression. Only one of the second and third expressions is evaluated. Every value computation and side effect associated with the first expression is sequenced before every value computation and side effect associated with the second or third expression.

Related

Post-increment operator behaviour w.r.t comma operator?

In the following code:
int main() {
int i, j;
j = 10;
i = (j++, j+100, 999+j);
cout << i;
return 0;
}
The output is 1010.
However shouldn't it be 1009, as ++ should be done after the whole expression is used?
The comma operator is a sequence point: as it says in the C++17 standard for example,
Every value computation and side effect associated with the left expression is sequenced
before every value computation and side effect associated with the right expression.
Thus, the effect of the ++ operator is guaranteed to occur before 999+j is evaluated.
++ should be done after the whole expression is used?
No. The postfix operator evaluates to the value of the old j and has the side effect of incrementing j.
Comma operator evaluates the second operand after the first operand is evaluated and its side-effects are evaluated.
A pair of expressions separated by a comma is evaluated left-to-right;
the left expression is a discarded- value expression (Clause 5)83.
Every value computation and side effect associated with the left
expression is sequenced before every value computation and side effect
associated with the right expression.
https://stackoverflow.com/a/7784819/2805305
Associativity of the comma operator is left to right.
So starting from j++, this will be evaluated first (j becomes 11)
Then j + 100 is evaluated (no use)
Then 999 + j is evaluated which is equal to 1010
This rightmost value is assigned to i
Thus, the output is 1010
Long Answer:
Built-in comma operator
The comma operator expressions have the form
E1 , E2
In a comma expression E1, E2, the expression E1 is evaluated, its
result is discarded (although if it has class type, it won't be
destroyed until the end of the containing full expression), and its
side effects are completed before evaluation of the expression E2
begins (note that a user-defined operator, cannot guarantee
sequencing) (until C++17).
This already answers your question, but I'll walk through it with reference to your code:
Start with something simple like
int value = (1 + 2, 2 + 3, 4 + 5); // value is assigned 9
Because ...the expression E1 is evaluated, its result is discarded... Here, since we have more than 2 operands, the associativity of the comma operator also comes into play.
However shouldn't it be 1009, as '++" should be done after the whole
expression is used?
Now see:
int j = 0;
int i = (j++, 9 + j);
Here, the value of i is 10 because ...and its side effects are completed before evaluation of the expression E2 begins... Hence, the incrementation of j has its effect before the evaluation of 9 + j.
I think now you can clearly understand why your
j = 10;
i = (j++, j+100, 999+j);
i is assigned a value of 1010.

Is ternary operator allowed to evaluate both operands in C++?

While porting some C code to Windows, I've discovered an interesting ternary operator behavior in MSVC++. It appears that compiler evaluates both branches around ? : in the following example:
#include <stdio.h>
struct S {
int x;
};
int getNum() {
printf("get num\n");
return 4;
}
int main(int argc, char **argv) {
struct S s = argc ? (struct S) { .x = getNum() } : (struct S) { .x = getNum() };
printf("%d\n", s.x);
return 0;
}
Prints:
get num
get num
4
But, GCC and Clang evaluate getNum() only once. Which behavior is correct or allowed by the standard?
According to C++11 §5.16.1 Conditional operator:
Conditional expressions group right-to-left. The first expression is
contextually converted to bool (Clause 4). It is evaluated and if it
is true, the result of the conditional expression is the value of the
second expression, otherwise that of the third expression. Only one
of the second and third expressions is evaluated. Every value
computation and side effect associated with the first expression is
sequenced before every value computation and side effect associated
with the second or third expression.
According to C11 §6.5.15 Conditional operator:
The first operand is evaluated; there is a sequence point between its
evaluation and the evaluation of the second or third operand
(whichever is evaluated). The second operand is evaluated only if
the first compares unequal to 0; the third operand is evaluated only
if the first compares equal to 0; the result is the value of the
second or third operand (whichever is evaluated), converted to the
type described below.

Does the ternary operator short circuit in a defined way

If you have the following:
if (x)
{
y = *x;
}
else
{
y = 0;
}
Then behavior is guaranteed to be defined since we can only dereference x if it is not 0
Can the same be said for:
y = (x) ? *x : 0;
This seems to work as expected (even compiled with -Wpedantic on g++)
Is this guaranteed?
Yes, only the second or third operand will be evaluated, the draft C++ standard section 5.16 [expr.cond] says:
Conditional expressions group right-to-left. The first expression is contextually converted to bool (Clause 4).
It is evaluated and if it is true, the result of the conditional expression is the value of the second expression,
otherwise that of the third expression. Only one of the second and third expressions is evaluated. Every value
computation and side effect associated with the first expression is sequenced before every value computation
and side effect associated with the second or third expression.

C++ nested conditional operator order of evaluation

For an expression like
x = a ? b : c ? d : e;
I understand that because the ?: operator has right associativity, the expression is grouped as
x = a ? b : (c ? d : e);
However, what about order of evaluation? Does associativity mean that the (c ? d : e) branch evaluated first, and then the answer of it passed as an argument to the left ?: operator? Or is a evaluated first, and then depending on that either b is returned or the (c ? d : e) branch is evaluated? Or is it undefined?
n3376 5.16/1
Conditional expressions group right-to-left. The first expression is
contextually converted to bool (Clause 4). It is evaluated and if it
is true, the result of the conditional expression is the value of the
second expression, otherwise that of the third expression. Only one of
the second and third expressions is evaluated. Every value computation
and side effect associated with the first expression is sequenced
before every value computation and side effect associated with the
second or third expression.
For the conditional operator:
the first operand is evaluated first;
either the second or the third (but not both) is evaluated depending on the value of the first.

Variable initialization in C++: a unique method

Recently I came across this piece of code. I don't know why I never saw this kind of syntax in all my "coding life".
int main()
{
int b;
int a = (b=5, b + 5);
std::cout << a << std::endl;
}
a has value of 10. What exactly is this way of initialization called? How does it work?
This statement:
int a = (b=5, b + 5);
Makes use of the comma operator. Per Paragraph 5.18/1 of the C++11 Standard:
[...] A pair of expressions separated by a comma is evaluated left-to-right; the left expression is a discarded value
expression (Clause 5).83 Every value computation and side effect associated with the left expression
is sequenced before every value computation and side effect associated with the right expression. The type
and value of the result are the type and value of the right operand; the result is of the same value category
as its right operand, and is a bit-field if its right operand is a glvalue and a bit-field. If the value of the right
operand is a temporary (12.2), the result is that temporary.
Therefore, your statement is equivalent to:
b = 5;
int a = b + 5;
Personally, I do not see a reason for using the comma operator here. Just initialize your variable the easily readable way, unless you have a good reason for doing otherwise.
operator , evaluates arguments one after another and return the last value
It may be used not only in initialization
The comma , operator allows you to separate expressions. The compount statement made by
exp1, exp2, ..., expn
evaluates to expn.
So what happens is that first b is set to 5 and then a is set to b + 5.
A side note: since , has the lowest precedence in the table of operators the semantics of
int a = b = 5, b+5;
is different from
int a = (b = 5, b+5);
because the first is parsed as (int a = b = 5), b + 5
When used in an expression the comma operator will evaluate all of its operands (left-to-right) and return the last.
The initialization is called copy initialization. If you ignore the complex expression on the right, it's the same as in:
int a = 10;
This is to be contrasted with direct initialization, which looks like this:
int a(10);
(It's possible that you were separately confused about how to evalue a comma expression. Please indicate if that's the case.)