initialization of 'unused' is skipped by 'goto label' - why do I get it for std::string but not for int?

StackOverflow https://stackoverflow.com/questions/22863950

Question

I bumped against this error in some code, and after some experimenting I stumbled upon this weirdness - I get it for std::string, but not for int.

For std::string I get error C2362: initialization of 'unused' is skipped by 'goto label':

{   goto label;
    std::string unused;
label:;
}

For int I don't get any error, however:

{   goto label;
    int unused = 10;
label:;
}

Why the difference? Is it because std::string has a non-trivial destructor?

Was it helpful?

Solution

This is covered in the draft C++ standard section 6.7 Declaration statement which says (emphasis mine):

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).

and provides the following example:

void f() {
  // ...
  goto lx; // ill-formed: jump into scope of a
ly:
  X a = 1;
  // ...
lx:
 goto ly; // OK, jump implies destructor
          // call for a followed by construction
          // again immediately following label ly
}

Although both cases should generate an error since your are bypassing an initialization in both cases, this however would have been fine:

goto label;
      int unused ;
label:

So Visual Studio is not correct here, both gcc and clang generate and error for this code, gcc says:

error:   crosses initialization of 'int unused'
       int unused = 10;
           ^

Of course Visual Studio can have extension like that as long as they document it but it is not portable to use such an extension, as I pointed out both clang and gcc generate an error for this.

We can find a rationale for why we don't want to jump across an initialization in defect report 467 which sought to have the same restriction added for local static variable (it was rejected):

[...]automatic variables, if not explicitly initialized, can have indeterminate (“garbage”) values, including trap representations, [...]

OTHER TIPS

A compiler error. Both are illegal. What is not illegal, however, is:

{
    goto label;
    int unused;
    unused = 10;
label:
    ;
}

Both std::string unused; and int unused = 10; have initializers (a default constructor in the case of std::string), and you're not allowed to jump around a definition with an initializer. Jumping around one without an initializer is probably allowed avoid breaking code like:

switch ( something )
{
    int i;
case 0:
    i = x;
    // ...
    break;

case 1:
    i = y;
    //  ...
    break;
//  ...
}

I wouldn't call this good code, but it wouldn't surprise me to find it in older C, and C++ does try not to break these sort of things.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top