0

From this FAQ: What are Aggregates and PODs and how/why are they special?

We have this part:

goto statement. As you may know, it is illegal (the compiler should issue an error) to make a jump via goto from a point where some variable was not yet in scope to a point where it is already in scope. This restriction applies only if the variable is of non-POD type. In the following example f() is ill-formed whereas g() is well-formed. Note that Microsoft compiler is too liberal with this rule - just issues a warning in both cases.

int f() {
  struct NonPOD { NonPOD(){}};
  goto label;
  NonPOD x;
label:
  return 0;
}

int g(){
  struct POD {int i;  char c;};
  goto label;
  POD x;
label:
  return 0;
}

I'd like to understand why the difference? It seems like it could be that even though the POD is declared after the goto it is already initialized and nothing more needs to be done whereas the non-POD is not initialized. Or am I barking up the wrong tree?

Community
  • 1
  • 1
Richard Johnson
  • 612
  • 1
  • 9
  • 20

2 Answers2

1

Goto can not jump over an initialization, unless it appears in a block, and you jump over the whole block.

For non-POD the ctor is called. That is necessary, and must happen at the place where the variable appears. If you could jump over it, the variable would be accessible with a broken state. And eventually its dtor would explode the program.

Balog Pal
  • 16,195
  • 2
  • 23
  • 37
  • So that implies that in the POD case the initialization has already been done but in the non-POD case it has not been done. – Richard Johnson Jun 18 '13 at 17:18
  • POD can not have a ctor - that is one of the requirements. But I think if you used {} init, that would fail too. – Balog Pal Jun 18 '13 at 17:29
  • Well, the constructor is implicit and it must have run at some point. The goto cannot jump over an initialization so the POD must have been initialized. I'm trying to figure out when that happens. – Richard Johnson Jun 18 '13 at 17:34
  • In your example POD is just that "plain old data", meaning it doesn't have a constructor, desctructor or virtual methods (or contents that has any of those - e.g. `std::string` inside a struct will make it a non-POD). The `x` in `g()` is uninitialized - it has got some random junk based on what happens to be on the stack inside it, but no initialization. – Mats Petersson Jun 18 '13 at 17:39
  • So you're saying the POD is uninitialized. If so, then the goto should not be able to jump over it. – Richard Johnson Jun 18 '13 at 17:41
  • It can for a POD, because it doesn't have a constructor, nor does it have a destructor. Those are the "initializations" that matter here. – Mats Petersson Jun 18 '13 at 18:19
  • Okay, so the difference between non-POD and POD lies in construction. PODs don't need to be constructed whereas non-PODs do. That's why you can memcpy a POD and have it come out right but you cannot be guaranteed that same operation with a non-POD. – Richard Johnson Jun 18 '13 at 18:26
1

In the case of f, the destructor for x (which is automatically provided by the compiler on the grounds of having a constructor, thus making the struct a non-POD type) will be called "on returning". Calling the destructor on an object that hasn't been constructed is not a good plan. If we make this code a sufficiently more complex, we could quite easily end up in a scenario where it's very complicated for the compiler to know which objects have been initialized and which have not, so it's safer to just simply forbid jumping over any initialization (another common case of this is when using a switch-statement, where some objects are introduced within each case:

switch(x)
{
   case 1:
      NonPod x;
      ..
      break;
   case 2: 
      ...
}

is a similar construct (and equally bad).

Mats Petersson
  • 126,704
  • 14
  • 140
  • 227