Topic: Base pointer to array of Derived (was Borland C++)


Author: jamshid@emx.cc.utexas.edu (Jamshid Afshar)
Date: 17 Oct 1993 00:58:09 -0500
Raw View
In article <1993Oct13.071658.4996@usage.csd.unsw.oz.au>,
Vladimir Gilbourd <s9100767@cumulus.csd.unsw.OZ.AU> wrote:
>Compile, please, and run two simple patterns. ( Definitions of classes are
>equal for both cases). As you will see the output will be different.

The code is like:

 #include <iostream.h>
 class B
 { public:
     virtual ~B() {cout<<"B::~B()\n";}
 };
 class D : public B
 { public:
    ~D() {cout<<"D::~D()\n";}
 };

 main() {
    B *pp;
    pp = new D[1];
    delete [] pp;
 }

Under one of the compilers Vladimir used, BC++ [3.1], the above
program does not call the D destructor.  Under a few other compilers,
the D destructor is called, just as if the code were:

 pp = new D;
 delete pp;

>Who can explain why Borland gives different outputs?

You're code has a very subtle error.  A `B*' can legally point to a B
object, to an object of a class derived from B, or to an array of B
objects.  The expression `new D[1]' allocates an array of D objects
and the assignment `B* pp = new D[1];' causes `pp' to point to the
first element of D.  That's perfectly fine.  The problems start when
you try to use `pp' as a pointer to an array (eg, pp[3] or
delete[]pp).  Since `pp' does not actually point to an array of `B'
objects, your use results in undefined behavior (eg, it might work, it
might sorta work, it might crash).

Apparently BC++ knows that when it deletes an array of objects, those
objects must be objects of the exact type `pp' points to.  So, BC++
doesn't bother to do a virtual destructor call.  I don't think there's
anything wrong with this optimization since it doesn't break correct
code.

Unfortunately, your error is, in general, impossible to catch at
compile time.  It's like the following error:

 void foo(B* p);  // what if foo() assumes `p' is an array?
 main() {
    D d[5];
    foo(d);  // woops
 }

The dangerous automatic conversion of "array of D" to "pointer to B"
is one of the many reasons to avoid general use of built-in arrays in
C++ (use an array class instead).  Btw, if you've never read the
comp.lang.c FAQ section on arrays and pointers, please do -- I'm sure
you'll find it very enlightening.

Jamshid Afshar