2

Currently I'm reading Think in C++.

I'm confused about the conditional storage allocation for an object.

As the code below, the goto and switch generate warning or an error.

But if-else works fine, which is conditionally passed through during execution.

So why there is no warning or error for if-else?

/* crosses initializaion error */  
#include <iostream>
using namespace std;
class X {
public:
    X();
};
X::X() {}

void f(int i) {
    if (i > 2) {
       X x1;
    } else {
       X x2; // why conditionally executed works fine?
    }
    if (i > 2) {
        goto jjump1;
    }
    //X x3;  // error coused by goto
    {X x3; //works fine}
jjump1:
    X x4;
    switch(i) {
      // case 1:    X x5; break;
     //case 2:  X x6; break; // error coused by switch
       {case 1: X x5; break;}
       {case 2: X x6; break;}//  solved

    }
 }
int main() {
    f(1);
    return 0;
}

UPDATE:

C++ doing so is to guarantee that an object cannot be created unless it is also initialized. But in the case of if-else how can both part of it be initialized as only one part of it will be go through?

As the C++ is following the practice in C of allocating the storage for a scope at the opening brace of that scope.

Here is my thought(I don't know what's wrong..):

But it's the same for switch and goto, only the token case need to be initialized but there is crosses initialization error. The if-else and switch both obey initializing the token branch only.

At last, I figured out the key word is scope. As the C++ is following the practice in C of allocating the storage for a scope at the opening brace of that scope. So the A program that jumps87 from a point where a variable with automatic storage duration is not in scope to a point where it is in scope is ill-formed unless the variable has scalar type, class type with a trivial default constructor and a trivial destructor, a cv-qualified version of one of these types, or an array of one of the preceding types and is declared without an initializer rule ensure that variables are initialized once allocated.

Thank you all.

luoluo
  • 5,353
  • 3
  • 30
  • 41
  • Why are you using `goto`? Why are you declaring objects in a code block and throwing them away? Why does the function `f` do nothing? – Ed Heal Jan 07 '14 at 03:20
  • I'm doing an experiment to figure out some detail about storage allocation. – luoluo Jan 07 '14 at 03:24

1 Answers1

4

You are not allowed to jump past the declaration of a variable unless it is scalar or it has a trivial default constructor, this is covered in the draft C++ standard section 6.7:

It is possible to transfer into a block, but not in a way that bypasses declarations with initialization. A program that jumps87 from a point where a variable with automatic storage duration is not in scope to a point where it is in scope is ill-formed unless the variable has scalar type, class type with a trivial default constructor and a trivial destructor, a cv-qualified version of one of these types, or an array of one of the preceding types and is declared without an initializer (8.5).

In the case of the switch one way to avoid this problem would be to create a scope using {} at each label like this:

switch(i)
{
   case 1: { X x5;  break; }
   case 2: { X x6;  break; }
}
Shafik Yaghmour
  • 154,301
  • 39
  • 440
  • 740
  • What I'm asking is why the `if-else` works fine? Isn't it some kind of jump through? – luoluo Jan 07 '14 at 03:31
  • 2
    @luoluo *if* is not a jump statement. The jump statements are `break`, `continue`, `return` and `goto` which are covered in section `6.6. Jump Statements`. The `if` statement is classified as a *selection statement*. The *body* of the *if* will have it's own scope and any variables declared in that local scope will not exist outside of it. – Shafik Yaghmour Jan 07 '14 at 03:34
  • But When I deleted the `break` in `switch`, there is still a `crosses initialization` error. Does this mean that `switch` belongs to `Jump statements` or may be converted to something like that? – luoluo Jan 07 '14 at 03:45
  • @luoluo it is because there is only one scope that covers all of the *case* labels, you can get around this in a *switch* by using `{}` at each label. I will update my answer. – Shafik Yaghmour Jan 07 '14 at 03:53
  • Then what's the benefit of this? – luoluo Jan 07 '14 at 04:11
  • @luoluo that is a broad question, they are techniques. Using them effectively though and recognizing when to use them takes a long time to master. Although in general, except in specialized cases like the Linux kernel you would avoid using *goto* and generally you would declare variables before the *switch* statement. – Shafik Yaghmour Jan 07 '14 at 04:19
  • But in the case of if-else how can both part of it be initialized as only one part of it will be go through? – luoluo Jan 07 '14 at 06:15
  • @luoluo You answered your own question: since only one branch will be taken per call to `f`, only one initialization needs to be taken account for. – HonkyTonk Jan 07 '14 at 06:55
  • But it's the same for switch, only the token case need to be initialized but there is `crosses initialization` error. The `if-else` and `switch` seem both obey `initialize the token branch`. – luoluo Jan 07 '14 at 07:42