31

Possible Duplicate:
Will using goto leak variables?

In the following example, when goto is called to go "backwards", the destructor of A is called. Why is it like that? Object a is not leaving its scope, is it? Does the standard say anything about this behavior regarding goto?

void f()
{
start:
    A a;
    goto start;
}
Community
  • 1
  • 1
Eric Z
  • 13,619
  • 5
  • 40
  • 65

4 Answers4

26

6.6 Jump statements [stmt.jump]

Paragraph 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 ]

I think the important part is:

or back past an initialized variable with automatic storage duration involves the destruction

Community
  • 1
  • 1
Martin York
  • 234,851
  • 74
  • 306
  • 532
14

The lifetime of object a starts from its declaration, and extends to the end of the block containing it.

This means that, in jumping back to before the declaration, you jump to a stack frame situations where the local didn't exist, so it must be destructed

  1. The point of declaration for a name is immediately after its complete declarator (Clause 8) and before its initializer (if any) , [...] (§ 3.3.2)

  2. A name declared in a block (6.3) is local to that block; it has block scope. Its potential scope begins at its point of declaration (3.3.2) and ends at the end of its block. A variable declared at block scope is a local variable. (§ 3.3.3)

sehe
  • 328,274
  • 43
  • 416
  • 565
12

Here is a relevant quote from the standard. It even includes an example that is almost identical to yours:

C++11 6.7 Declaration statement [stmt.dcl]

2 Variables with automatic storage duration (3.7.3) are initialized each time their declaration-statement is executed. Variables with automatic storage duration declared in the block are destroyed on exit from the block (6.6).

3 It is possible to transfer into a block, but not in a way that bypasses declarations with initialization. A program that jumps 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). [ 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
}

—end example ]

As explained in the example, the goto implies destruction. The declaration-statement (A a; in your code) means the constructor is re-executed after each jump.

NPE
  • 438,426
  • 93
  • 887
  • 970
  • +1 very enlightening quote too – sehe Dec 15 '11 at 15:11
  • 1
    It does not constitute exit from the block. As this would cause the destruction of all variables in the block. It only causes destruction of variables that it jumps back past the initialization of. The [stmt.jump] explicitly states that a goto will cause destruction that is enough. – Martin York Dec 15 '11 at 15:27
  • Hey aix, as to the quote 6.7 3, why "..is ill-formed unless the variable has scalar type..and is declared without an initializer"? In the above example, if X is int w/o initializer, the program is still ill-formed because the definition of a is bypassed by "goto lv", isn't it? – Eric Z Dec 15 '11 at 15:30
1

Simply put... start: is a label and declares a[nother] scope

Assuming start is as <0x00003000>, A a will be at <0x00003000> + some_offset say <0x00003004>.

goto start will ask the PC (Program Counter) to go to the address of start which occurs before the declaration of A -- outside it's scope -- hence "destroy a" calls the destructor.

iGbanam
  • 5,465
  • 4
  • 36
  • 62