#include <iostream>
using namespace std;
struct Base
{
virtual ~Base()
{
cout << "~Base(): " << b << endl;
}
int b = 1;
};
struct Derived : Base
{
~Derived() override
{
cout << "~Derived(): " << d << endl;
}
int d = 2;
};
int main()
{
Base* p = new Derived[4];
delete[] p;
}
The output is as follws: (Visual Studio 2015 with Clang 3.8)
~Base(): 1
~Base(): 2
~Base(): -2071674928
~Base(): 1
Why does polymorphism not apply on arrays in C++?
Given,
Base* p = Derived[4];
the C++11 Standard makes
delete [] p;
to be undefined behavior.
5.3.5 Delete
...
2 ... In the second alternative (delete array) if the dynamic type of the object to be deleted differs from its static type, the behavior is undefined.
From a memory layout point of view, it also makes sense why delete [] p;
will result in undefined behavior.
If sizeof(Derived)
is N
, new Derived[4]
allocates memory that will be something like:
+--------+--------+--------+--------+
| N | N | N | N |
+--------+--------+--------+--------+
In general, sizeof(Base)
<= sizeof(Derived)
. In your case, sizeof(Base)
< sizeof(Derived)
since Derived
has an additional member variable.
When you use:
Base* p = new Derived[4];
you have:
p
|
V
+--------+--------+--------+--------+
| N | N | N | N |
+--------+--------+--------+--------+
p+1
points to someplace in the middle of the first object since sizeof(Base) < sizeof(Derived)
.
p+1
|
V
+--------+--------+--------+--------+
| N | N | N | N |
+--------+--------+--------+--------+
When the destructor is called on p+1
, the pointer does not point to the start of an object. Hence, the program exhibits symptoms of undefined behavior.
A Related Problem
Due to the differences in sizes of Base
and Derived
, you cannot iterate over the elements of the dynamically allocated array using p
.
for ( int i = 0; i < 4; ++i )
{
// Do something with p[i]
// will not work since p+i does not necessary point to an object
// boundary.
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With