Upon each transfer of control (including sequential execution of statements)
within a function from point
P to point
Q,
all block variables with automatic storage duration
that are active at
P and not at
Q are destroyed in the reverse order of their construction
. Then, all block variables with automatic storage duration
that are active at
Q but not at
P are initialized in declaration order;
unless all such variables have vacuous initialization (
[basic.life]),
the transfer of control shall not be a jump
.
When a
declaration-statement is executed,
P and
Q are the points immediately before and after it;
when a function returns,
Q is after its body
. [
Example 1:
void f() {
goto lx;
ly:
X a = 1;
lx:
goto ly;
}
—
end example]
Dynamic initialization of a block variable with
static storage duration or
thread storage duration is performed
the first time control passes through its declaration; such a variable is
considered initialized upon the completion of its initialization
. If the
initialization exits by throwing an exception, the initialization is not
complete, so it will be tried again the next time control enters the
declaration
. If control enters the declaration concurrently while the variable is
being initialized, the concurrent execution shall wait for completion
of the initialization
. [
Note 2:
A conforming implementation cannot introduce
any deadlock around execution of the initializer
. Deadlocks might still be caused by the program logic;
the implementation need only avoid deadlocks
due to its own synchronization operations
. —
end note]
If control
re-enters the declaration recursively while
the variable is being initialized, the behavior is undefined
. [
Example 2:
int foo(int i) {
static int s = foo(2*i);
return i+1;
}
—
end example]
An object associated with
a block variable with static or thread storage duration
will be destroyed if and only if it was constructed
.