Topic: jumps and scopes


Author: dougm@zamenhof.rice.edu (Doug Moore)
Date: 30 Aug 91 01:17:15 GMT
Raw View
Well, despite a reply from Dr. Stroustrup on this question, I remain
unenlightened.  Maybe somebody out there can help.

When should a destructor be called for an object?  Some relevant
quotes from the manual:

<begin quote>
r.6.6 Jump statements
  On exit from a scope (however accomplished), destructors are called for
all constructed class objects in that scope that have not yet been
destroyed.  This applies to both explicitly defined objects and
temporaries.

r.6.7 Declaration Statement
  Destruction of local variables declared in the block is done on exit
from the block. ... Transfer out of ... a block ... involves the
destruction of auto variables declared at the point transferred from
but not at the point transferred to.
  It is possible to transfer into a block, but not in a way that
causes initializations not to be done.  It is illegal to jump bast a
declaration with an explicit or implicit initializer unless the
declaration is in an inner block that is not entered....

An auto variable constructed under a condition is destroyed under than
condition and cannot be accessed outside that condition.
<end quote>

In his reply to my question about code essentially like this:

switch(i)
{
  case 0:
    sometype d;
    // use d
    break;
  case 1:
    // don't use d
    break;
};

Dr. Stroustrup wrote
<begin quote>
The example is legal. The point is that the switch jumps past the
complete use of a declaration (construction AND destruction) exactly
as if the declaration had been enclosed in a block that was completely
bypassed.
<end quote>

My problem is that, as I see it, the variable d is still in scope in
case 1.  It is true that in case 0, the break; will cause a destructor
to be called for d, but I believe that a destructor should be called
for d at the second break; as well.  Which is dangerous, which is why
I believe the program to be illegal.

Since he designed the language and I didn't, I figure he's probably
right, and this code is legal.  But consider this mostly similar code:

switch(i)
{
  case 0:
    sometype d;
    // use d
    if (some_condition)
      break;
    // use d
    // note - no break;
  case 1:
    // don't use d
    break;
};

Is this code legal?  If not, what rule does it violate that the first
code fragment doesn't?

If so, and I think it must be legal if the first fragment is, then
where are destructors for d called?  Surely at the first break; where
else?  Not at the last break, or case 1 is unsafe.  If right before
the label for case 1, then isn't the code between cases 0 and 1 some
kind of newfangled implicit block?  Or, is there some kind of
condition constructor at the second break; of the form "if d was
constructed, destroy it."?

For what it's worth, g++ 1.37.1 calls the destructor for d in both
cases.  A version of Sun C++ 2.0 from 1989 won't compile such things,
but with a "sorry, not implemented: non trivial declaration in switch
statement (try enclosing it in a block)" message.  Of course, my whole
point is that such things should always be enclosed in blocks.

Thanks for any clarification you can offer.

Doug Moore
dougm@rice.edu