54

Consider the following code:

void foo()
{
    {
        CSomeClass bar;

        // Some code here...

        goto label;

        // and here...
    }

label:
    // and here...
}

Will the destructor of bar be called ?

Alexandre C.
  • 55,948
  • 11
  • 128
  • 197
  • Why do you need to know this? `goto` makes sense in generated code, but there you can and should avoid objects with destructors anyway. – MSalters Jul 05 '10 at 13:43
  • 15
    @MSalters: that doesnt makes sence at all, why should you avoid objects with destructors? – Viktor Sehr Jul 05 '10 at 13:44
  • 1
    @Viktor: Let me expand the second part of the sentence: _In generated code_, you can and should avoid objects with destructors anyway. The canonical use of `goto` is in generated FSM code. Here jumps occur backwards and forwards, without regard for state code states that just happens to be in the middle. FSM states simply aren't linear, but C++ code must be. – MSalters Jul 07 '10 at 08:52
  • 4
    It is to be noted that `break` and `continue` have a very similar, to not say exactly the same effect as a `goto`, only the *label* is automatically generated by the compiler at the right place. Yet, a `break` within a `for()` loop is expected to go the right thing, so should the `goto`. – Alexis Wilke Oct 23 '14 at 05:04

5 Answers5

83

The C++ Standard says:

On exit from a scope (however accomplished), destructors (12.4) are called for all constructed objects with automatic storage duration (3.7.2) (named objects or temporaries) that are declared in that scope, in the reverse order of their declaration.

So the answer is "yes".

  • 2
    Thanks for answering the question concisely. The whole "don't do this" doesn't help understand code you've inherited and are trying to understand. – Pascal Laferrière Oct 05 '22 at 21:01
37

Yes, they will be called.

Update: (it's okay to do this, gotos is not worse than throwing dummy exceptions or using bools/ifs to get out of things. A simple goto inside a function don't make it spaghetti code.)

Viktor Sehr
  • 12,825
  • 5
  • 58
  • 90
  • 15
    +1 to negate the egotistical student who felt the need to downvote because they personally think gotos are evil. Gotos have valid uses, people, regardless of what your professors told you. – KevenK Jul 05 '10 at 13:50
  • 2
    "it's okay to do this, gotos is not worse than throwing dummy exceptions or using bools/ifs to get out of things" Throwing a dummy exception is a terrible way to do this (throwing exceptions is generally extremely expensive) and if it's between that and gotos, I'd definitely prefer gotos. However, writing functions for these cases is certainly the best way to go. – stinky472 Jul 05 '10 at 14:24
  • 3
    @KevinK - Gotos may have valid uses in theory, but they're extremely rare in practice. I would argue that if it looks like you have to use a goto, the situation at least merits close examination. And for beginning devs, I would suggest avoiding them is a good discipline to learn. – jwismar Jul 05 '10 at 14:32
  • 6
    @jwismar If a goto helps with code readability, i say go ahead and use it. An example of a legitimate use would be to escape from nested loops. – aCuria Jul 05 '10 at 15:39
  • I discussed gotos in [this answer](http://programmers.stackexchange.com/a/133523/33478). – Keith Thompson Apr 10 '13 at 17:28
  • @aCuria, I have to agree, many other languages offer things like `break 3` or `break – Alexis Wilke Oct 23 '14 at 05:08
7

Yes, as everyone else says. C++ specifies/mandates this.

But just to add to that, for completeness: if your goto uses the computed-goto extension found in some compilers -- gcc, clang, possibly others but not including MSVC last I knew -- whether or not the object's destructor will be called is pretty hazy. When a goto goes to a single location, it's very clear what destructors must be called before the control-flow transfer. But with a computed goto, different destructors might need to dynamically be called, to give the "expected" semantics. I'm not sure what compilers that implement this extension do, in those cases. My memory from encountering this is that clang warns when a computed-goto might leave a scope with an object with a non-trival destructor, claiming the destructor won't be called. In some cases that might be fine, in others not. I don't know offhand what other compilers do. Just be aware of the issue if you want to use computed gotos in concert with objects with non-trivial destructors.

Jeff Walden
  • 7,008
  • 2
  • 38
  • 55
  • Thanks. I only use computed gotos from C, and in very rare situations. – Alexandre C. Apr 10 '13 at 18:36
  • 4
    For those who wonder what computed goto is, see [here](https://gcc.gnu.org/onlinedocs/gcc/Labels-as-Values.html) or [here](https://stackoverflow.com/a/45380228/3075942). – user May 28 '19 at 17:34
6

1) Yes. 2) Don't do this.

Elaboration: conceptually, this is no different from leaving a loop via a break. goto, however, is strongly, strongly discouraged. It is almost never necessary to use goto, and any use should be scrutinized to find out what's going on.

jwismar
  • 12,164
  • 3
  • 32
  • 44
  • 1
    2) you do this when you escape loops actually. – Alexandre C. Jul 05 '10 at 13:48
  • 18
    Actually, goto makes sense in quite a few circumstances. –  Jul 05 '10 at 13:51
  • 3
    A break is nicer. At least I know I won't be jumping upwards. – DanDan Jul 05 '10 at 13:53
  • +1 and for the original question, a function would probably be the best bet. – stinky472 Jul 05 '10 at 14:23
  • 3
    The worst about `goto`, `break` and `continue` is that a "return" at the end of a block won't mean "control can't reach beyond this". For that reason, i always try to avoid all three. I personally don't see much difference between `break` and `goto`. Sure there is a bit more worseness in `goto`, but it doesn't add much. All of these have their uses, but all of these complicate the code – Johannes Schaub - litb Jul 05 '10 at 21:28
2

Although the destructor is meant to be called, note that gcc has a bug:

If your code is of the following form, where you return the class and also do a jump that should cause it to be destructed, the destructor is skipped.

CSomeClass foo()
{
    label:
    CSomeClass bar;

    // Some code here...

    if (someCondition)
       goto label; // if this jump is taken, bar is not destructed in gcc

    return bar;
}