8

I have a snippet of code here, of which I don't understand why it results in a segmentation fault on line 22 (delete[] statement). Can you please explain this to me?

#include<iostream>
#include<memory>

class A {
  size_t a[1000];

  public:
    virtual ~A() { }
};

class B : public A {
  public:
    float b;
    virtual ~B() { }
};


int main(int argc, char** argv){

  A *b;

  b = new B[10];
  delete[] b;

  return 0;
}

Strangely, if class B doesn't have any member variables (i.e. I comment out the line "float b;") then the code just runs fine.

What's my mistake here?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
user3617992
  • 359
  • 1
  • 8
  • 1
    https://stackoverflow.com/questions/6171814/why-is-it-undefined-behavior-to-delete-an-array-of-derived-objects-via-a-base – Nemanja Boric Jan 07 '18 at 13:27

3 Answers3

11

Simply put, you have undefined behavior. You aren't providing delete[] with a pointer you got from new[]. You may think you do, but for the pointers to be the same in the array version, their static type has to match. You converted the pointer into a pointer to a base class.

Practically, when you don't have that added float, your implementation probably maintains sizeof(B) == sizeof(A). So the destructor and deallocation function invocations don't do anything immediately harmful. But it's just as undefined.

StoryTeller - Unslander Monica
  • 165,132
  • 21
  • 377
  • 458
  • 1
    I thought that this is what virtual destructors are made for? So I take it that virtual destructors only work with new/delete, but not with new[]/delete[]? – user3617992 Jan 07 '18 at 13:30
  • 1
    @user3617992 - Virtual destructors are for pointers to single objects. Arrays aren't polymorphic types. – StoryTeller - Unslander Monica Jan 07 '18 at 13:31
  • 1
    @user3617992 Yes, this is what virtual destructors are for, however the trouble happens because they can not be called properly when array contains items that are different from `delete` operator expectations. – user7860670 Jan 07 '18 at 13:33
3

delete[] b; will attempt to delete an array of A objects, not an array of B objects. If class B does not have any member variables then sizes of these arrays happen to be the same which probably allows you to dodge the bullet.

When delete is invoked it will access vtable of the each item stored in the array to call a virtual destructor. It will assume that size of each item is sizeof(A) so if the sizeof(B) is different then accessing vtable of the second item will be performed at the wrong offset.

user7860670
  • 35,849
  • 4
  • 58
  • 84
1

If you want polymorphism with an array, then you need to create an array of pointers to the base class.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
dimm
  • 1,792
  • 11
  • 15