[intro.execution] (original) (raw)
6 Basics [basic]
6.9 Program execution [basic.exec]
6.9.1 Sequential execution [intro.execution]
Such an object exists and retains its last-stored value during the execution of the block and while the block is suspended (by a call of a function, suspension of a coroutine ([expr.await]), or receipt of a signal).
A constituent expression is defined as follows:
- The constituent expression of an expression is that expression.
- The constituent expression of a conversion is the corresponding implicit function call, if any, or the converted expression otherwise.
- The constituent expressions of a braced-init-list or of a (possibly parenthesized) expression-listare the constituent expressions of the elements of the respective list.
[Example 1: struct A { int x; };struct B { int y; struct A a; }; B b = { 5, { 1+1 } };
The constituent expressions of the initializerused for the initialization of b are 5 and 1+1.
— _end example_]
The immediate subexpressions of an expression E are
- the constituent expressions of E's operands ([expr.prop]),
- any function call that E implicitly invokes,
- if E is a lambda-expression ([expr.prim.lambda]), the initialization of the entities captured by copy and the constituent expressions of the initializer of the init-captures,
- if E is a function call or implicitly invokes a function, the constituent expressions of each default argument ([dcl.fct.default]) used in the call, or
- if E creates an aggregate object ([dcl.init.aggr]), the constituent expressions of each default member initializer ([class.mem]) used in the initialization.
A subexpression of an expression E is an immediate subexpression of E or a subexpression of an immediate subexpression of E.
The potentially-evaluated subexpressions of an expression, conversion, or initializer E are
- the constituent expressions of E and
- the subexpressions thereof that are not subexpressions of a nested unevaluated operand ([expr.context]).
A full-expression is
- an unevaluated operand,
- a constant-expression ([expr.const]),
- an immediate invocation ([expr.const]),
- an init-declarator ([dcl.decl]) (including such introduced by a structured binding ([dcl.struct.bind])) or a mem-initializer ([class.base.init]), including the constituent expressions of the initializer,
- an invocation of a destructor generated at the end of the lifetime of an object other than a temporary object ([class.temporary]) whose lifetime has not been extended,
- the predicate of a contract assertion ([basic.contract]), or
- an expression that is not a subexpression of another expression and that is not otherwise part of a full-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.
Conversions applied to the result of an expression in order to satisfy the requirements of the language construct in which the expression appears are also considered to be part of the full-expression.
For an initializer, performing the initialization of the entity (including evaluating default member initializers of an aggregate) is also considered part of the full-expression.
[Example 2: struct S { S(int i): I(i) { } int& v() { return I; } ~S() noexcept(false) { } private: int I;}; S s1(1); void f() { S s2 = 2; if (S(3).v()) { } bool b = noexcept(S(4)); } struct B { B(S = S(0));}; B b[2] = { B(), B() }; — _end example_]
[Note 2:
The evaluation of a full-expression can include the evaluation of subexpressions that are not lexically part of the full-expression.
For example, subexpressions involved in evaluating default arguments ([dcl.fct.default]) are considered to be created in the expression that calls the function, not the expression that defines the default argument.
— _end note_]
Reading an object designated by a volatileglvalue ([basic.lval]), modifying an object, calling a library I/O function, or calling a function that does any of those operations are allside effects, which are changes in the state of the execution environment.
Evaluation of an expression (or a subexpression) in general includes both value computations (including determining the identity of an object for glvalue evaluation and fetching a value previously assigned to an object for prvalue evaluation) and initiation of side effects.
When a call to a library I/O function returns or an access through a volatile glvalue is evaluated, the side effect is considered complete, even though some external actions implied by the call (such as the I/O itself) or by the volatile access may not have completed yet.
Sequenced before is an asymmetric, transitive, pair-wise relation between evaluations executed by a single thread ([intro.multithread]), which induces a partial order among those evaluations.
Given any two evaluations A and_B_, if A is sequenced before B(or, equivalently, B is sequenced after A), 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 3:
The execution of unsequenced evaluations can overlap.
— _end note_]
Evaluations A and B areindeterminately sequenced when either A is sequenced before_B_ or B is sequenced before A, but it is unspecified which.
[Note 4:
Indeterminately sequenced evaluations cannot overlap, but either can be executed first.
— _end note_]
An expression _X_is said to be sequenced before an expression Y if every value computation and every side effect associated with the expression _X_is sequenced before every value computation and every side effect associated with the expression Y.
Everyvalue computation andside effect associated with a full-expression is sequenced before every value computation and side effect associated with the next full-expression to be evaluated.35
Except where noted, evaluations of operands of individual operators and of subexpressions of individual expressions are unsequenced.
[Note 5:
In an expression that is evaluated more than once during the execution of a program, unsequenced and indeterminately sequenced evaluations of its subexpressions need not be performed consistently in different evaluations.
— _end note_]
The value computations of the operands of an operator are sequenced before the value computation of the result of the operator.
The behavior is undefined if
- a side effect on a memory location ([intro.memory]) or
- starting or ending the lifetime of an object in a memory location
is unsequenced relative to
- another side effect on the same memory location,
- starting or ending the lifetime of an object occupying storage that overlaps with the memory location, or
- a value computation using the value of any object in the same memory location,
and the two evaluations are not potentially concurrent ([intro.multithread]).
[Note 6:
Starting the lifetime of an object in a memory location can end the lifetime of objects in other memory locations ([basic.life]).
— _end note_]
[Note 7:
The next subclause imposes similar, but more complex restrictions on potentially concurrent computations.
— _end note_]
[Example 3: void g(int i) { i = 7, i++, i++; i = i++ + 1; i = i++ + i; i = i + 1; union U { int x, y; } u;(u.x = 1, 0) + (u.y = 2, 0); } — _end example_]
When invoking a function f (whether or not the function is inline), every argument expression and the postfix expression designating _f_are sequenced before every precondition assertion of f ([dcl.contract.func]), which in turn are sequenced before every expression or statement in the body of f, which in turn are sequenced before every postcondition assertion of f.
For each
- function invocation,
- evaluation of an await-expression ([expr.await]), or
- evaluation of a throw-expression ([expr.throw])
F, each evaluation that does not occur within _F_but is evaluated on the same thread and as part of the same signal handler (if any) is either sequenced before all evaluations that occur within _F_or sequenced after all evaluations that occur within F;36if F invokes or resumes a coroutine ([expr.await]), only evaluations subsequent to the previous suspension (if any) and prior to the next suspension (if any) are considered to occur within F.
Several contexts in C++ cause evaluation of a function call, even though no corresponding function call syntax appears in the translation unit.
[Example 4:
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, regardless of the syntax of the expression that calls the function.
If a signal handler is executed as a result of a call to the std::raisefunction, then the execution of the handler is sequenced after the invocation of the std::raise function and before its return.
[Note 8:
When a signal is received for another reason, the execution of the signal handler is usually unsequenced with respect to the rest of the program.
— _end note_]