Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does polymorphism not apply on arrays in C++? [duplicate]

#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++?

like image 518
xmllmx Avatar asked Dec 13 '16 03:12

xmllmx


1 Answers

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.
}
like image 71
R Sahu Avatar answered Oct 16 '22 04:10

R Sahu