I'm reading thinking in c++ chapter 6 initialization & cleanup. The author said that:
It's actually more likely that the compiler will follow the practice in C of allocating all the storage for a scope at the opening brace of that scope. It doesn't matter because, as a programmer, you can't access the storage until it has been defined. Although the storage is allocated at the beginning of the block, the constructor call doesn't happen until the sequence point where the object is defined because the identifier isn't available until then. The compiler even checks to make sure that you don't put the object definition where the sequence point only conditionally passes through it, such as in a switch statement or somewhere a goto can jump past it.
And then the author gives an example as following:
class X {
public:
X();
};
X::X() {}
void f(int i) {
if(i < 10) {
//! goto jump1; // Error: goto bypasses init
}
X x1; // Constructor called here
jump1:
switch(i) {
case 1 :
X x2; // Constructor called here
break;
// case 2 : // Error: case bypasses init
X x3; // Constructor called here
break;
}
}
int main() {
f(9);
f(11);
}///:~
I don't understand why the above code is OK? According to my understanding, x2
can be bypassed initialization if i
is not 1
.
Supplement:
This sentence "It'a actually more likely that the compiler will follow the practice in C of allocating all the storage for a scope at the opening brace of that scope." also confused me.
According to the author's description, at the opening brace of the switch
, the compiler has already allocated space for x2
and x3
. If this is the case, there is an opportunity for x2
to be uninitialized(case 1 is not satisfied).
According to my understanding, x2 can be bypassed initialization if i is not 1.
No, either the case 1
is executed, and x2
is defined and then destroyed at the end of the switch
block, or no case is executed and the entire switch
block does nothing, so x2
is not in scope, so it isn't initialized but it can't be referred to either. So either it exists and is safe to use, or it doesn't exist.
C++ object initialization and destruction semantics are completely jump-safe (exception, goto , switch and loop constructs included).
(The only notable exception is inherited from the C standard library (setjmp/longjmp))
6.6 Jump statements
2 On exit from a scope (however accomplished), objects with automatic storage duration (3.7.3) that have been constructed in that scope are destroyed in the reverse order of their construction. [ Note: For temporaries, see 12.2. —end note ] Transfer out of a loop, out of a block, or back past an initialized variable with automatic storage duration involves the destruction of objects with automatic storage duration that are in scope at the point transferred from but not at the point transferred to. (See 6.7 for transfers into blocks). [ Note: However, the program can be terminated (by calling std::exit() or std::abort() (18.5), for example) without destroying class objects with automatic storage duration. —end note ]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With