[comp.lang.c++] Incorrect handling of destructors in Turbo C++

kent@humu.nosc.mil (Kent K. Kuriyama) (03/25/91)

There seems to be a bug in the code that Turbo C++ 1.00 generates.
In the following program the destructor routine should only be called
once.

------------
# include <stdio.h>

class A {
  protected:
    int i;
  public:
    A();
    ~A();
};

A::A()
{
  printf("Constructor called\n");
}

A::~A()
{
  printf("Destructor called\n");
}

void sub(A a)
{
  printf("in sub\n");
}

void main()
{
  A a;

  printf("before call\n");
  sub(a);
  printf("after call\n");
}
------------

When this program is executed:

------------
Constructor called
before call
in sub
after call
Destructor called
Destructor called
------------

Am I wrong to think that the destructor should only be called once?

Kent Kuriyama                          Voice (808) 257-1618
Naval Ocean Systems Center             FAX   (808) 257-1685
Hawaii Laboratory                      Box 997, Code 531   
kent@nosc.mil                          Kailua, HI   96734  

wmm@world.std.com (William M Miller) (03/25/91)

kent@humu.nosc.mil (Kent K. Kuriyama) writes:
> void main()
> {
>   A a;
>
>   printf("before call\n");
>   sub(a);
>   printf("after call\n");
> }
> ------------
>
> When this program is executed:
>
> ------------
> Constructor called
> before call
> in sub
> after call
> Destructor called
> Destructor called
> ------------
>
> Am I wrong to think that the destructor should only be called once?

Yes.  C++ has, by default, the call-by-value semantics of C.  When you
called "sub(a)", an object was created to hold the copy of "a" that was
actually passed to "sub()."  Since you didn't provide a constructor that
could be used for this purpose (it's called a "copy constructor" and is
declared as "A::A(const A&)"), the compiler generated a default one for you
that just did a bit-for-bit copy.  Naturally, the default one didn't have a
printf() call in it, so its execution didn't show up in your output.  Of the
two destructors, one is for the copy passed to "sub()," the other is for
"a."

-- William M. Miller, Glockenspiel, Ltd.
   wmm@world.std.com

horstman@mathcs.sjsu.edu (Cay Horstmann) (03/26/91)

In article <546@humu.NOSC.Mil> you write:
>There seems to be a bug in the code that Turbo C++ 1.00 generates.
>In the following program the destructor routine should only be called
>once.
>
>------------
># include <stdio.h>
>
>class A {
>  protected:
>    int i;
>  public:
>    A();
>    ~A();
>};
>
>A::A()
>{
>  printf("Constructor called\n");
>}
>
>A::~A()
>{
>  printf("Destructor called\n");
>}
>
>void sub(A a)
>{
>  printf("in sub\n");
>}
>
>void main()
>{
>  A a;
>
>  printf("before call\n");
>  sub(a);
>  printf("after call\n");
>}
>------------
>
>When this program is executed:
>
>------------
>Constructor called
>before call
>in sub
>after call
>Destructor called
>Destructor called
>------------
>

You are wrong.

You didn't supply a copy constructor for A (i.e. no A(const A&)). That
made the argument in sub constructed with a bitwise copy but destroyed
with the ~A(). The only funny thing is that Turbo routinely translates
a function call sub(a) into A temp = a; sub( temp ) and changes 
void sub( A a ) into void sub( A& a ). It beats me why they do it, but
they do, and that is why the destructor is called both times after
sub exits.

I ran into some cases when the destructor didn't get called enough, but
I have a hard time reproducing it in a small and short program. If anyone 
has one, let me know!

Cay