Object gets destructed before constructed

Object gets destructed before constructed

Post by Jason A. Antonel » Mon, 01 Jul 1996 04:00:00



The following behavior doesn't quite seem right.  If an object is created
on the stack in one of the cases of a switch statement, the object's
destructor gets implicitly called when the switch block ends.  However, if
we skip over the case that declares the object, the object's destructor
still gets implicitly called when the switch block ends.  This causes
problems- specifically due to a destructors probable dependence on data
that it expected the constructor to initialize.  And the constructor only
gets called in the case statement it was declared in.

I understand that all cases in a switch share the same local block, and I
know that my problem could be easily solved by putting a couple curly
brackets in,  but it seems to me that this is still a problem (I don't
have any of my C++ books, so I can't even try to look it up)

Included is sample source/execution that demonstrates problem.

Execution #1: GOOD CASE
Enter a number 1 or 2: 1
case 1
duh constructor called
duh destructor called

Execution #2: PROBLEM CASE
Enter a number 1 or 2: 2
case 2
duh destructor called

SOURCE:
#include <iostream.h>

class Duh {
public:
   Duh() { cerr << "duh constructor called\n"; }
   ~Duh() { cerr << "duh destructor called\n"; }

Quote:};

int main()
{
   int x;

   cout << "Enter a number 1 or 2: ";
   cin >> x;

   switch (x) {
      case 1:
         cerr << "case 1\n";
         Duh duh;
         break;
      case 2:
         cerr << "case 2\n";
         break;
   }

Quote:}

--

http://sdcc8.ucsd.edu/~jantonel
UC San Diego, Computer Engineering
 
 
 

Object gets destructed before constructed

Post by Andrew Shear » Mon, 01 Jul 1996 04:00:00




>However, if
>we skip over the case that declares the object, the object's destructor
>still gets implicitly called when the switch block ends.  This causes
>problems- specifically due to a destructors probable dependence on data
>that it expected the constructor to initialize.  And the constructor only
>gets called in the case statement it was declared in.

>I understand that all cases in a switch share the same local block, and I
>know that my problem could be easily solved by putting a couple curly
>brackets in,  but it seems to me that this is still a problem (I don't
>have any of my C++ books, so I can't even try to look it up)

Metrowerks C++ now warns about this; it says "illegal jump past
initializer." Maybe warnings are turned off.

I'm not sure why this isn't a full-fledged error.

--
Andrew Shearer


 
 
 

Object gets destructed before constructed

Post by Stephen C. Gilard » Tue, 02 Jul 1996 04:00:00




>I understand that all cases in a switch share the same local block, and I
>know that my problem could be easily solved by putting a couple curly
>brackets in,  but it seems to me that this is still a problem (I don't
>have any of my C++ books, so I can't even try to look it up)

You're absolutely right.  I've seen it said here that Metrowerks has
been notified of the problem several times.  After being bitten by it
and tracking it down myself, I notified them in a message to which
they assigned "Reference No.  ES46065".

I have not received a bug number for it, though, and I should have.

The tech support person who wrote back supplied a workaround.

However, his wording was "the correct syntax is [a switch including
extra curly brackets]".  This implied that the syntax I was reporting
a failure with was "incorrect".  That's not true.

Also, he did not seem realize that even if a workaround is available,
the current behavior is buggy and needs to be fixed.

Metrowerks: how about fixing this or at least listing it somewhere as
a known bug and giving the bug number to those of us who waste our
time tracking it down and reporting it for the nth time.

THIS BUG MAKES LEGAL C++ CODE FAIL AT RUNTIME.  IT'S SIGNIFICANT!

--Steve

Stephen C. Gilardi
SQ Software

 
 
 

Object gets destructed before constructed

Post by Stephen C. Gilard » Tue, 02 Jul 1996 04:00:00




>Metrowerks C++ now warns about this; it says "illegal jump past
>initializer." Maybe warnings are turned off.

>I'm not sure why this isn't a full-fledged error.

I used the CW9 C/C++ compiler (MW C/C++ PPC version 1.5) with all warnings
turned on to compile the following program:

--------------------------------------------------------------------------
#include <iostream>

void foo(int i);

class bar
{
public:
        bar() { cout << "bar constructor called.\n"; }
        ~bar() { cout << "bar destructor called.\n"; }

Quote:};

main()
{
        cout << "foo(1)\n";
        foo(1);
        cout << "\nfoo(2)\n";
        foo(2);
        cout << "\nfoo(3)\n";
        foo(3);
        return 0;

Quote:}

void foo(int i)
{
        switch (i) {
                case 1:
                        cout << "1 selected\n";
                        break;
                case 2:
                        bar theBar;
                        cout << "2 selected\n";
                        break;
                case 3:
                        cout << "3 selected\n";
                        break;
        }              
Quote:}

--------------------------------------------------------------------------

The program compiled without warning, linked and ran.  The output was:

--------------------------------------------------------------------------
foo(1)
1 selected

foo(2)
bar constructor called.
2 selected
bar destructor called.

foo(3)
3 selected
bar destructor called.
--------------------------------------------------------------------------

The problem is that for case 3, theBar's destructor was called without
its constructor having been called.

I would have no problem if for "foo(3)", both the constructor and
destructor for bar were called.

I would have no problem if for "foo(1)", both the constructor and
destructor for bar were called.

In either case, I could use curly brackets to enforce a scope if the
extra constructor/destructor calls were a problem in my program.

However, to cause an object's destructor to be called without ensuring
that the object's constructor was also called seems an unthinkable
thing for a correct C++ compiler to do without complaint.  If the
program itself is a not a legal C++ program, then the compiler should
issue an error message or at the very least issue a warning.

As it is, the MW C/C++ quietly produces object code that is likely to
crash at runtime.  I think this is unacceptable.

If the program above is not a legal C++ program, that's very valuable
information and I'm very happy to have learned it.  Whether or not it
is a legal C++ program, I believe that the compiler can improve its
behavior when compiling it.

I look forward to some definitive word from Metrowerks one way or
another.

--Steve

Stephen C. Gilardi
SQ Software

 
 
 

Object gets destructed before constructed

Post by Lars Fa » Tue, 02 Jul 1996 04:00:00



> Metrowerks C++ now warns about this; it says "illegal jump past
> initializer." Maybe warnings are turned off.

> I'm not sure why this isn't a full-fledged error.

My copy of CW9 doesn't give a warning about the switch. All warnings are
enabled and the snippet compiles nicely (*). This of course is wrong,
because the snippet is not C++ and should produce an _error_
[stmt.dcl]/3.

(*) ... except it falsely warns about a missing return, this is another
bug in the C++ compiler [basic.start.main]/5. If there is no return in
main, the _compiler_ must insert a return. Since it warns about a
missing return one can conclude that it didn't and that is a compiler
bug. This is rather a nice feature in a compiler. Automatic self bug
detection and report.

--

 
 
 

Object gets destructed before constructed

Post by Lars Fa » Tue, 02 Jul 1996 04:00:00



Quote:> The following behavior doesn't quite seem right.  If an object is created
> on the stack in one of the cases of a switch statement, the object's
> destructor gets implicitly called when the switch block ends.  However, if
> we skip over the case that declares the object, the object's destructor
> still gets implicitly called when the switch block ends.  This causes
> problems- specifically due to a destructors probable dependence on data
> that it expected the constructor to initialize.  And the constructor only
> gets called in the case statement it was declared in.

> I understand that all cases in a switch share the same local block, and I
> know that my problem could be easily solved by putting a couple curly
> brackets in,  but it seems to me that this is still a problem (I don't
> have any of my C++ books, so I can't even try to look it up)

This is an old and well known bug in the MW++ compiler. For some reason
never mentioned in the release notes. The compiler should not accept
your code, because it is not C++. The language rule is old, not what MW
likes to call an "extension". The rule was the same in the ARM six years
ago.

  6.7  Declaration statement [stmt.dcl]

3 It  is  possible  to  transfer  into  a  block,  but not in a way that
  bypasses  declarations  with  initialization.   A program that jumps2)
  from a point where a local variable with automatic storage duration is
  not  in scope to a point where it is in scope is ill-formed unless the
  variable has POD type (_basic.types_) and is declared without an  ini-
  tializer (_dcl.init_).  [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]

  _________________________
  2) The transfer from the condition of a switch statement to a case la-
  bel is considered a jump in this respect.

--

 
 
 

Object gets destructed before constructed

Post by Andrew Shear » Tue, 02 Jul 1996 04:00:00





>> Metrowerks C++ now warns about this; it says "illegal jump past
>> initializer." Maybe warnings are turned off.

>> I'm not sure why this isn't a full-fledged error.

>My copy of CW9 doesn't give a warning about the switch. All warnings are
>enabled and the snippet compiles nicely (*). This of course is wrong,
>because the snippet is not C++ and should produce an _error_
>[stmt.dcl]/3.

I should have retested the warning with CW9 (though I'm not near my
development machine now). In previous versions, that warning worked. Very
old versions of CodeWarrior (up to CW5 time, give or take a couple of
releases) didn't complain, and apparently the latest version doesn't
either.

--
Andrew Shearer

 
 
 

Object gets destructed before constructed

Post by MW R » Tue, 02 Jul 1996 04:00:00




>the current behavior is buggy and needs to be fixed.

>Metrowerks: how about fixing this or at least listing it somewhere as
>a known bug and giving the bug number to those of us who waste our
>time tracking it down and reporting it for the nth time.

This is indeed a bug the switch is ill formed and should be fixed in CW
10.  I don't have any reason this isn't listed as a known but in the
release notes or it not having been fixed before.  

Ron

--
METROWERKS                   Ron Liechty

 
 
 

Object gets destructed before constructed

Post by Robert Fish » Wed, 03 Jul 1996 04:00:00




>This is indeed a bug the switch is ill formed and should be fixed in CW
>10.  I don't have any reason this isn't listed as a known but in the
>release notes or it not having been fixed before.  

I'm sorry, Ron, but this isn't good enough. This seems like a *very*
serious problem to me. Metrowerks should state unequivocally that this
*will* be fixed in CW10, if not by a net-borne patch before hand.

After all, isn't this one of the major points of C++? Constructor &
destructor calls should all be automatic and correct. If the compiler
can't guarantee this for a particular syntax, it should most definitely
generate an error.

I can understand putting off things like full draft standard conformance
for things like direct-to-SOM, but I can't understand putting off bug
fixes like this.

--


Renegade Software/ModelOffice    http://www.modeloffice.com

 
 
 

Object gets destructed before constructed

Post by Stephen C. Gilard » Wed, 03 Jul 1996 04:00:00




>This is indeed a bug the switch is ill formed and should be fixed in CW
>10.  I don't have any reason this isn't listed as a known but in the
>release notes or it not having been fixed before.  

In summary, then, the following construct is not legal C++:

    switch (i) {
        case 1:
            cout << "1 selected\n";
            break;
        case 2:
            bar theBar;
            cout << "2 selected\n";
            break;
        case 3:
            cout << "3 selected\n";
            break;
    }      

The problem with it is that it contains an implicit "goto" from the
curly bracket after the "switch" to the label "case 3:".  That "goto"
jumps into the scope of "theBar" and thus bypasses the point in the
program where "theBar" is constructed.

The "bug" is that the CW9 C++ compiler compiles this illegal code
without giving an error message.

This summary is based on my current understanding which I got from
reading the posts in this thread and reading the draft standard.

I was wrong in my original assertion that the compiler was incorrectly
compiling legal C++ code.

--Steve

Stephen C. Gilardi
SQ Software

 
 
 

Object gets destructed before constructed

Post by MW R » Thu, 04 Jul 1996 04:00:00






>>This is indeed a bug the switch is ill formed and should be fixed in CW
>>10.  I don't have any reason this isn't listed as a known but in the
>>release notes or it not having been fixed before.  

>I'm sorry, Ron, but this isn't good enough. This seems like a *very*
>serious problem to me. Metrowerks should state unequivocally that this
>*will* be fixed in CW10, if not by a net-borne patch before hand.

Please understand I can't speak for engineering, so there was a delay in
my replying.  Now that I have a reply from them it is...

This *WILL* be fixed in CW10, if not by a net-borne patch before that.

Ron

--
METROWERKS                   Ron Liechty