14

I get segmentation fault exception on the next code:

class A {
public:
    A() {}
    virtual ~A(){}
    double m_d;
};
class B : public A {
public:
    B() {}
    virtual ~B(){}
    int x;
};
int main()
{
    A* ptr = new B[5];
    delete[] ptr;
    return 0;
}

If delete d'tors, no exception. Expected to NOT receive an exception.

Compiler: g++ (Ubuntu 11.2.0-19ubuntu1) 11.2.0

8
  • 7
    A* ptr = new B[5]; yeah that's a bad idea. The 2 objects have different sizes so any attempt to access anything other than ptr[0] will fail horribly Commented Nov 22, 2022 at 19:14
  • 1
    @MaciejPolański it's a gcc only crash - live - godbolt.org/z/dMeo9sWaM Commented Nov 22, 2022 at 19:15
  • 2
    delete[] ptr; invokes undefined behavior because ptr points to an array of B objects, not an array of A objects Commented Nov 22, 2022 at 19:21
  • 9
    If delete d'tors, no exception. -- "If I remove the brakes, the car runs smoothly". Commented Nov 22, 2022 at 19:25
  • 2
    An array of a class is a different type than the class itself, and inheritance does follow through when the type changes, so while a B is-a A an array of B is-not-a array of A. Commented Nov 22, 2022 at 19:41

2 Answers 2

13

Array delete doesn't respect virtual destructors. Attempting to pass a base class pointer to it causes undefined behavior.

[expr.delete]/2

... In a single-object delete expression, the value of the operand of delete may be a null pointer value, a pointer value that resulted from a previous non-array new-expression, or a pointer to a base class subobject of an object created by such a new-expression. If not, the behavior is undefined. In an array delete expression, the value of the operand of delete may be a null pointer value or a pointer value that resulted from a previous array new-expression. If not, the behavior is undefined.

Note the second list excluding "base class subobject..." part.

[expr.delete]/3

... In an array delete expression, if the dynamic type of the object to be deleted is not similar to its static type, the behavior is undefined.

Where "static type" is the type as determined at compile-time, "dynamic type" is the type of the most-derived object determined at runtime, and "similar" more or less means "the same type", but allows some differences in constness and more.

Sign up to request clarification or add additional context in comments.

1 Comment

The undefined behavior aspect of this cannot be overstated. I compiled and ran the OP's code without a segfault, and this might easily be mistaken for this code being safe to expect to work as expected.
7

This is not allowed, as described here: Why is it undefined behavior to delete[] an array of derived objects via a base pointer?

Excerpt: C++03 Standard under 5.3.5 [expr.delete] p3: 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

I also made, out of curiosity, logging version:

#include <iostream> 

class A {
public:
    A() {}
    virtual ~A(){ std::cout << m_d << " ; ";}
    double m_d {0.5};
};
class B : public A {
public:
    B() {}
    virtual ~B(){ std::cout << x << " : "; }
    int x {2};
};
int main()
{
    A* ptr = new B[5];
    delete[] ptr;
    std::cout << "Hi, nothing crashed here!\n";
    return 0;
}

https://godbolt.org/z/Y7xGdKd3f

Clang: calls base class destructor using incorrect data

2.07634e-317 ; 0.5 ; 9.88131e-324 ; 2.07634e-317 ; 0.5 ; Hi, nothing crashed here!

Gnu: politely crashes

Program returned: 139

M$: works as expected :)

2 : 0.5 ; 2 : 0.5 ; 2 : 0.5 ; 2 : 0.5 ; 2 : 0.5 ; Hi, nothing crashed here

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.