P
Peter Julian
Prawit Chaivong said:Hi All,
There is code here.
------------------------------------------------------------------
class Base{
public:
Base(){}
virtual ~Base(){}
private:
int a;
};
class Derived : public Base{
public:
Derived(){}
virtual ~Derived(){}
private:
int b;
};
int main()
{
Base* pb = new Derived[10];
delete[] pb; // <-- crash HERE.
return 0;
}
-------------------------------------------------------------------pointer. Because size of both are not similar.From code, I know that I shouldn't delete Derived object by its parent
But my question is when I remove keyword 'virtual' out of
destructor(both classes). This program is not crash anymore.
I just want to know why it's not crash if its dtor is not virtual.
Without the virtual destructor:
You are then deleting 10 times the equivalent of a new Base allocation.
Which is undefined behaviour here since the objects are not of Base type.
Can you say: memory leak? Note that pb is *not* a pointer to an array (pb
points to a single Base object). That too is undefined behaviour when you
delete [] pb.
When the destructor in Base is made virtual and an array of Base pointers is
implemented:
fact #1: an array is not responsible to track whether its elements are Base
or Derived.
fact #2: an array requires an appropriate default constructor. Otherwise the
following will fail:
Base* pb[10];
fact #3: OO programming says that each element knows what type it actually
is through polymorphism. The container doesn't care. In your case, thats a
container of Base pointers. What those pointers actually point_to is
irrelevent as far as the array is concerned.
fact #3: to delete each element in a container of base-class pointers, you
need to delete the elements, not the container. Its not the container that
was allocated on the heap, its the elements that were newed.
fact #4: A derived class should initialize its Base class in the derived
class's initialization list.
So...
#include <iostream>
class Base
{
public:
Base() : a(0) { std::cout << "Base ctor invoked.\n"; }
virtual ~Base() { std::cout << "Base d~tor invoked.\n"; }
private:
int a;
};
class Derived : public Base
{
public:
Derived() : Base(), b(0) { std::cout << "\tDerived ctor invoked.\n"; }
~Derived() { std::cout << "\tDerived d~tor invoked.\n"; }
private:
int b;
};
int main()
{
const int size = 5;
Base* barray[size]; // container is allocated on the stack
std::cout << "*** array element allocations ***\n";
for (int i = 0; i < size; ++i)
{
barray = new Derived(); // elements are allocated on the heap
}
std::cout << "\n*** array element destructions:***\n";
for (int j = 0; j < size; ++j)
{
delete barray[j] ;
}
return 0;
}
/*
*** array element allocations ***
Base ctor invoked.
Derived ctor invoked.
Base ctor invoked.
Derived ctor invoked.
Base ctor invoked.
Derived ctor invoked.
Base ctor invoked.
Derived ctor invoked.
Base ctor invoked.
Derived ctor invoked.
*** array element destructions ***
Derived d~tor invoked.
Base d~tor invoked.
Derived d~tor invoked.
Base d~tor invoked.
Derived d~tor invoked.
Base d~tor invoked.
Derived d~tor invoked.
Base d~tor invoked.
Derived d~tor invoked.
Base d~tor invoked.
*/
________________________________________
to confirm that polymorphism does indeed occur lets alternate the element
type for each element in the array:
....
int main()
{
Base* barray[5];
std::cout << "*** array element allocations ***\n";
barray[0] = new Derived();
barray[1] = new Base();
barray[2] = new Derived();
barray[3] = new Base();
barray[4] = new Derived();
std::cout << "\n*** array element destructions:***\n";
for (int j = 0; j < 5; ++j)
{
delete barray[j] ;
}
return 0;
}
/* output:
"*** array element allocations ***
Base ctor invoked.
Derived ctor invoked.
Base ctor invoked.
Base ctor invoked.
Derived ctor invoked.
Base ctor invoked.
Base ctor invoked.
Derived ctor invoked.
"*** array element allocations *** // destructions....
Derived d~tor invoked.
Base d~tor invoked. // barray[0] ... a Derived object
Base d~tor invoked. // barray[1] ... a Base object
Derived d~tor invoked.
Base d~tor invoked. // barray[2] ... a Derived object
Base d~tor invoked. // barray[3] ... a Base object
Derived d~tor invoked.
Base d~tor invoked. // barray[4] ... a Derived object
*/