Is an Incremented Variable Reusable in a tie Call? - c++

So I understand that re-usage of a variable that has been post incremented is undefined behavior in a function call. My understanding is this is not a problem in constructors. My question is about tie which is oddly halfway between each.
Given: pair<int, int> func() can I do:
tie(*it++, *it) = func();
Or is that undefined behavior?

Since C++17, this code has unspecified behavior. There are two possible outcomes:
the first argument is the result of dereferencing the original iterator, the second argument is the result of dereferencing the incremented iterator; or
the first argument and the second argument are both the result of dereferencing the original iterator.
Per [expr.call]/8:
[...] The initialization of a parameter, including every associated
value computation and side effect, is indeterminately sequenced with
respect to that of any other parameter. [...]
So the second argument to tie may be either the result of dereferencing the incremented iterator or the original iterator.
Prior to C++17, the situation was a bit complicated:
if both ++ and * invoke a function (e.g., when the type of it is a sophisticated class), then the behavior was unspecified, similar to the case since C++17;
otherwise, the behavior was undefined.
Per N4140 (C++14 draft) [expr.call]/8:
[ Note: The evaluations of the postfix expression and of the
arguments are all unsequenced relative to one another. All side
effects of argument evaluations are sequenced before the function is
entered (see [intro.execution]). — end note ]
Thus, the code was undefined behavior because the evaluation of one argument was unsequenced with the other. The evaluation of the two arguments may overlap, resulting in a data race. Unless it is specified otherwise ...
Per N4140 [intro.execution]/15:
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 ] Every evaluation
in the calling function (including other function calls) that is not
otherwise specifically sequenced before or after the execution of the
body of the called function is indeterminately sequenced with respect
to the execution of the called function.9 Several
contexts in C++ cause evaluation of a function call, even though no
corresponding function call syntax appears in the translation unit.
[
Example: Evaluation of a new expression invokes one or more allocation and constructor functions; see [expr.new]. For another
example, invocation of a conversion function ([class.conv.fct]) can
arise in contexts in which no function call syntax appears. —
end example ] The sequencing constraints on the execution of the called function (as described above) are features of the function
calls as evaluated, whatever the syntax of the expression that calls
the function might be.
9)
In other words, function executions do not interleave with each
other.
Thus, if the operators are actually function calls, then the behavior is similarly unspecified.

Related

Order of evaluation of expressions in a function call

Given a function call func(E1, E2, E3) where E1 etc are arbitrary expressions, is it true that each expression is indeterminately sequenced with respect to each other expression, or are all the expressions unsequenced (i.e. the evaluations can overlap)?
I've looked at the cppreference page on this and it, in rule 15, uses the sentence
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.
which I don't think is quite the same as what I'm asking as the initialisation of the parameter is just the last step in evaluation of the parameter's expression.
But rule 21 which is talking about something else seems to imply that each sub-expression in a function call is indeterminately sequenced
Every expression in a comma-separated list of expressions in a
parenthesized initializer is evaluated as if for a function call
(indeterminately-sequenced)
So I'm a bit confused and any guidance is appreciated.
C++17 states in
8.2.2 Function call [expr.call]
4 ... The initialization and destruction of each parameter occurs within
the context of the calling function.
5 ... Note: All side effects of argument evaluations are sequenced before the
function is entered
5 ... The initialization of a parameter, including every associated value
computation and side effect, is indeterminately sequenced with respect
to that of any other parameter.
I hope this (my bolding) is clear enough.
(ref: n4659, final C++17 draft)

Function interleaving in pre C++17

Look at this simple function call:
f(a(), b());
According to the standard, call order of a() and b() is unspecified. C++17 has the additional rule which doesn't allow a() and b() to be interleaved. Before C++17, there was no such rule, as far as I know.
Now, look at this simple code:
int v = 0;
int fn() {
int t = v+1;
v = t;
return 0;
}
void foo(int, int) { }
int main() {
foo(fn(), fn());
}
With C++17 rules, v surely will have the value of 2 after the call of foo. But, it makes me wonder, with pre-C++17, is the same guaranteed? Or could it be that v ends up 1? Does it make a difference, if instead of int t = v+1; v = t;, we just have v++?
Functions calls were not allowed to interleave in previous versions as well.
Quoting from C++11 final draft (n3337)
1.9 Program execution [intro.execution]
...
15. ...
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 ]
Every evaluation in the calling function (including other function calls) that is not otherwise specifically sequenced before or after the execution of the body of the called function is indeterminately sequenced with respect to the execution of the called function9.
9) In other words, function executions do not interleave with each other.
Similar wording can be found in the final draft of the C++14 version as well.
v must be 2 in all versions of C++ (and C). The function fn() must be executed twice, and clearly each time it executes it will increment v. There is no multithreading here, no data race, and no possibility for fn() to be executed only partially and then interrupted while the other invocation of fn() proceeds.
C++17 has the additional rule which doesn't allow a() and b() to be interleaved. Before C++17, there was no such rule, as far as I know.
There were rules that applied here, though the wording and some details have grown more exact.
C++03 [intro.execution]/8:
Once the execution of a function begins, no expressions from the calling function are evaluated until execution of the called function has completed. [footnote 8]
[footnote 8]: In other words, function executions do not interleave with each other.
Though you could argue this doesn't actually say anything about other functions called from the calling function in the text, and footnotes are officially not normative.
C++11 changed the wording, largely because it introduced multithreading semantics. C++11 and C++14 [intro.execution]/15, emphasis mine:
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] Every evaluation in the calling function (including other function calls) that is not otherwise specifically sequenced before or after the execution of the body of the called function is indeterminately sequenced with respect to the execution of the called function. [footnote 9]
[footnote 9] In other words, function executions do not interleave with each other.
This wording, I think, leaves no doubt, at least in most cases.
C++17 [intro.execution]/18:
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. For each function invocation F, for every evaluation A that occurs within F and every evaluation B that does not occur within F but is evaluated on the same thread and as part of the same signal handler (if any), either A is sequenced before B or B is sequenced before A. [footnote 10] [Note: If A and B would not otherwise be sequenced then they are indeterminately sequenced. - end note]
[footnote 10] In other words, function executions do not interleave with each other.
This is a much more general statement about all evaluations in separate functions, not just arguments in a function call. But as far as I know, this more precise wording just clarifies some possibly ambiguous cases, but doesn't really change semantic behavior much.
I suspect we are confusing two concepts. Call order was only fixed within expressions in c++17. Interleaving of the statements in a function between 2 calls of functions has always been disallowed, though when the optimiser gets hold of your code, only the effect is guaranteed.
If you write a() ; b() then a() will be fully executed before b is then fully executed. Same if you write a(), b() or a() && b()
If you write a() + b() then there is no guarantee prior to c++17 that a() will be executed before b(), but there is a guarantee that whichever is executed first will be fully completed before the other is executed.
If you write c(a(), b()) it [is my understanding] that again there is no guarantee that a() will be executed before b(), but there /is/ the guarantee that the effects of the first executed function (whichever that is) will complete before the second is started, and of course there is the guarantee that c() will not be executed until both a() and b() have completed.
The optimiser should honour the intent of that guarantee, though it may take the statements of a() and b(), and even c(), and intermingle them, the effect of running the code should be the same as if they were run in sequence. Could the -O0 code do a() then b() and the -O3 code do b() then a()? Perhaps, though that would make the debugging quite difficult, so I would hope not.
The compiler only has to give the effect in the final result, and it is possible in multithreading for another thread to observe the effects of consecutive lines of code occur out of order unless specific thread-aware constructs are used.
It is my understanding that the optimiser can't allow the specific effects of a(), b(), and c() to appear to occur out of order between each function, though prior to c++17 the order of a() and b() is not well defined - all effects of b() might occur before all effects of a().

std::make_shared() change in C++17

In cppref, the following holds until C++17:
code such as f(std::shared_ptr<int>(new int(42)), g()) can cause a
memory leak if g gets called after new int(42) and throws an
exception, while f(std::make_shared<int>(42), g()) is safe, since
two function calls are never interleaved.
I'm wondering which change introduced in C++17 renders this no longer applicable.
The evaluation order of function arguments are changed by P0400R0.
Before the change, evaluation of function arguments are unsequenced relative to one another. This means evaluation of g() may be inserted into the evaluation of std::shared_ptr<int>(new int(42)), which causes the situation described in your quoted context.
After the change, evaluation of function arguments are indeterminately sequenced with no interleaving, which means all side effects of std::shared_ptr<int>(new int(42)) take place either before or after those of g(). Now consider the case where g() may throw.
If all side effects of std::shared_ptr<int>(new int(42)) take place before those of g(), the memory allocated will be deallocated by the destructor of std::shared_ptr<int>.
If all side effects of std::shared_ptr<int>(new int(42)) take place after those of g(), there is even no memory allocation.
In either case, there is no memory leak again anyway.
The P0145R3 paper (which was accepted into C++17) refines the order of evaluation of several C++ constructs, including
Postfix expressions are evaluated from left to right. This includes functions calls and member
selection expressions
Specifically, the paper adds the following text to 5.2.2/4 paragraph of the standard:
The postfix-expression is sequenced before each expression in the
expression-list and any default argument. Every value computation and
side effect associated with the initialization of a parameter, and the
initialization itself, is sequenced before every value computation and
side effect associated with the initialization of any subsequent
parameter.

How can we predict the output of the following C++ Program [duplicate]

This question already has answers here:
Undefined behavior and sequence points
(5 answers)
Closed 6 years ago.
I am confused about the output of the code.
It depends on what compiler i run the code. Why is it so?
#include <iostream>
using namespace std;
int f(int &n)
{
n--;
return n;
}
int main()
{
int n=10;
n=n-f(n);
cout<<n;
return 0;
}
Running it on the Ubuntu terminal with g++, the output is 1 whereas running it on Turbo C++ ( the compiler we used in school) gives output as 0.
In C++03, modifying a variable and also using its value in the same expression, without an intervening C++03 sequence point, was Undefined Behavior.
C++03 §5/4:
” 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.
Undefined Behavior, UB, provides the compiler with an opportunity to optimize, because it can assume that UB does not occur in a valid program.
However, with all the myriad UB rules of C++ it's difficult to reason about source code.
In C++11 sequence points were replaced with sequenced before, indeterminately sequenced and unsequenced relations:
C++11 §1.9/3
” Given any two evaluations A and B, if
A is sequenced before B, then the execution of A shall precede the execution of B. If A is not sequenced before
B and B is not sequenced before A, then A and B are unsequenced. [Note: The execution of unsequenced
evaluations can overlap. —end note ] Evaluations A and B are indeterminately sequenced when either A
is sequenced before B or B is sequenced before A, but it is unspecified which.
And with the new C++11 sequence relationship rules the modification in the function in the code in question is indeterminately sequenced with respect to the use of the variable, and so the code has unspecified behavior rather than Undefined Behavior, as noted by Eric M Schmidt in a comment to (the first version of) this answer. Essentially that means that there is no danger of nasal daemons or other possible UB effects, and that the behavior is a reasonable one. The two possible behaviors here are that the modification via the function call is done before the use of the value, or that it's done after the use of the value.
Why it's unspecified behavior:
C++11 §1.9/15:
” Every evaluation in the calling function (including other function calls) that is not otherwise specifically
sequenced before or after the execution of the body of the called function is indeterminately sequenced with
respect to the execution of the called function.
What “unspecified behavior” means:
C++11 §1.3.25:
” unspecified behavior
Behavior, for a well-formed program construct and correct data, that depends on the implementation
[Note: The implementation is not required to document which behavior occurs. The range of possible
behaviors is usually delineated by this International Standard. —end note ]
Why the modification effected by the assignment is not problematic:
C++11 §5.17/1
” In all cases, the assignment is sequenced after the value
computation of the right and left operands, and before the value computation of the assignment expression.
This is also quite different from C++03.
As the rather drastic edit of this answer shows, following Eric's comment, this kind of issue is not simple! The main advice I can give is to as much as possible just Say No™ to effects governed by subtle or very complex rules, the corners of the language. Simple code has a better chance of being correct, while so called clever code does not have a good chance of being significantly faster.

Why is this undefined behaviour?

Here's the sample code:
X * makeX(int index) { return new X(index); }
struct Tmp {
mutable int count;
Tmp() : count(0) {}
const X ** getX() const {
static const X* x[] = { makeX(count++), makeX(count++) };
return x;
}
};
This reports Undefined Behavior on CLang build 500 in the static array construction.
For sake of simplification for this post, the count is not static, but it does not change anything. The error I am receiving is as follows:
test.cpp:8:44: warning: multiple unsequenced modifications to 'count' [-Wunsequenced]
In C++11, this is fine; each clause of an initialiser list is sequenced before the next one, so the evaluation is well-defined.
Historically, the clauses might have been unsequenced, so the two unsequenced modifications of count would give undefined behaviour.
(Although, as noted in the comments, it might have been well-defined even then - you can probably interpret the standard as implying that each clause is a full-expression, and there's a seqeuence point at the end of each full-expression. I'll leave it to historians to debate the finer points of obsolete languages.)
Update 2
So after some research I realized this was actually well defined although the evaluation order is unspecified. It was a pretty interesting putting the pieces together and although there is a more general question covering this for the C++11 case there was not a general question covering the pre C++11 case so I ended up creating a self answer question, Are multiple mutations of the same variable within initializer lists undefined behavior pre C++11 that covers all the details.
Basically, the instinct when seeing makeX(count++), makeX(count++) is to see the whole thing as a full-expression but it is not and therefore each intializer has a sequence point.
Update
As James points out it may not be undefined pre-C++11, which would seem to rely on interpreting the initialization of each element as a full expression but it is not clear you can definitely make that claim.
Original
Pre-C++11 it is undefined behavior to modify a variable more than once within a sequence point, we can see that by looking at the relevant section in an older draft standard would be section 5 Expressions paragraph 4 which says (emphasis mine):
[...]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.
In the C++11 draft standard this changes and to the following wording from section 1.9 Program execution paragraph 15 says (emphasis mine):
Except where noted, evaluations of operands of individual operators and of subexpressions of individual expressions are unsequenced. [...] If a side effect on a scalar object is unsequenced relative to either another side effect on the same scalar object or a value computation using the value of the same scalar object, the behavior is undefined.
and we can see that for initializer lists from section 8.5.4 List-initialization paragraph 4 says:
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.
Because it this case, the , is NOT a sequence point, but acts more like a delimiter in the initialization of the elements of the array.
In other words, you're modifying the same variable twice in a statement without sequence points (between the modifications).
EDIT: thanks to #MikeSeymour: this is an issue in C++03 an before. It seems like in C++11, the order of evaluation is defined for this case.