4

I have this code who gives me a segmentation fault 3 or more elements. I tested on vs and clang and works (loop ends and binary ends with no errors). I 'm doing something wrong? or its a g++ bug?

If i change the delete[] line to delete[] static_cast<B*>(a); it works on g++ too. But, in real cases, I will do not know the real type so I can not cast to anything.

class A {
public:
  virtual ~A() {}
  virtual int x() = 0;
};

class B : public A {
public:
  B() : _x(1) {}
  virtual ~B() {}
  virtual int x() { return _x; }
private:
  int _x;
};

int main(int argc, char * argv[]) {
  A * a;
  for (unsigned int i = 1; i <= 10; ++i) {
    a = new B[i];
    delete[] a;
  }
return 0;
}
NathanOliver
  • 171,901
  • 28
  • 288
  • 402
roberpot
  • 61
  • 2
  • You can only `delete[]` what you `new`-ed. You `new`ed an array of `B`s. That's the only thing you can `delete[]`, then. – Sam Varshavchik Oct 05 '18 at 21:11
  • 1
    And this is why `std::vector` and `std::unique_ptr` should be the first go toes when needing dynamic allocations. – NathanOliver Oct 05 '18 at 21:13
  • If a major compiler such as g++ had an issue with the toy code you posted, thousands of programmers would have reported the issue. – PaulMcKenzie Oct 05 '18 at 21:17
  • 1
    See https://stackoverflow.com/questions/6171814/why-is-it-undefined-behavior-to-delete-an-array-of-derived-objects-via-a-base for an explanation of why you can not delete an array using a pointer to the elements base type – nos Oct 05 '18 at 21:30

2 Answers2

4

I 'm doing something wrong? or its a g++ bug?

The behavior of your program is undefined:

If the static type of the object that is being deleted differs from its dynamic type (such as when deleting a polymorphic object through a pointer to base), and if the destructor in the static type is virtual, the single object form of delete begins lookup of the deallocation function's name starting from the point of definition of the final overrider of its virtual destructor. Regardless of which deallocation function would be executed at run time, the statically visible version of operator delete must be accessible in order to compile. In other cases, when deleting an array through a pointer to base, or when deleting through pointer to base with non-virtual destructor, the behavior is undefined.

Edgar Rokjān
  • 17,245
  • 4
  • 40
  • 67
  • The "In other cases" there looks important. It seems to imply that there are some cases in which the bolded statement isn't true. (Or is "In other cases" one of three possibilities, rather than a qualifier for two?) – Joseph Sible-Reinstate Monica Oct 05 '18 at 21:16
  • 2
    @JosephSible I think it should be read as: "In other cases: ". So the bolded statement is one of those cases. – Edgar Rokjān Oct 05 '18 at 21:18
  • Ah, that is correct. The actual standard explains that more clearly than cppreference.com does. I'll post a quote from that too. – Joseph Sible-Reinstate Monica Oct 05 '18 at 21:20
  • So, in a real-world example, the user would either allocate an array of the correct type of pointer, or build a container-of-base-pointers one element at a time, and delete it likewise one at a time. Does that sound right? – Tim Randall Oct 05 '18 at 21:28
  • @TimRandall In a real world example I would start with either a container or a smart pointer in order not to debug memory leaks in the applications a few months later :) – Edgar Rokjān Oct 05 '18 at 22:01
1

From the C++ standard:

In a single-object delete expression, if the static type of the object to be deleted is different from its dynamic type, the static type shall be a base class of the dynamic type of the object to be deleted and the static type shall have a virtual destructor or the behavior is undefined. In an array delete expression, if the dynamic type of the object to be deleted differs from its static type, the behavior is undefined.

(emphasis added) That's exactly what you're doing when you delete[] a;, and a segmentation fault is definitely a possible result of undefined behavior.