In C++, if pointer to base is passed to the delete expression, and the destructor of base is not virtual, the behavior is undefined. Anything at all can happen. The compiler isn't required to justify itself anymore than when you step outside of array bounds.
Why does this happen? What's the logic behind this?
A base pointer to a derived object is still an instance of that derived object. You are just telling the compiler that you want to treat it as a certain way. Therefore, the derived object still gets created and so it has to be destroyed.
OP wrote:
Also, why If if set non-virtual ~Base() and virtual ~Derived() the program crashes?
C++ supports different paradigms. Traditional (dynamic) inheritance is activated when a class has a virtual function. Such classes get a vtable. It's a table of pointers to functions. Each call to a virtual function goes is redirected thru this table.
In your case, the vtable for Derived (and Base) have one entry, the entry for the destructor.
You really should have written:
1 2 3 4 5
int main()
{
Base* base = new Base();
Base* derived = new Derived();
Base* in = new Derived();
The system will know that derived holds a Derived, even though it's declared to be of type Base.
You don't need to think in terms of "CPU", but in terms of what is required by the standard. Your code evokes undefined behavior, so it is not valid (or is "ill-formed" in standardese.)
What happens in terms of CPU? What is it trying to do that can't do?
Read your error code. My guess is that you are getting an invalid address exception or something similar. But the whole problem with undefined behavior is that we don't know what the system running the code is going to do so it's impossible for us to say.
Guys i'm just trying to understand the REASON of this
How it works?
IF I set the Base's destr as non-virtual and the Derived classes destr as virtual... why doesnt the computer just call the Derived virtual destructor and only then calls the Base non-virtual destr?
delete takes a pointer. It doesn't know what type of object is pointed to, and if the object it points to doesn't have a virtual destructor, it has no way to know that there is another destructor that needs to be invoked.
The object it points to is a Derived, which HAS a virtual destructor.
It's the Base that has NOT
We said that if the Base destructor AND the Derived destructor are non-virtual then DELETE will only call the Base destructor (without calling Derived's one)
In my case, the Base destructor is STILL non-virtual.
But this time I set the Derived destructor as virtual and this made the difference (crash)
If ~Base() isn't virtual, ~Derived() will not be called.
I don't quite understand why so many people have answered this and you're still asking the same question. Perhaps you should all read the answers that have been provided.
The answers don't satisfy my question
I'm expecting WHY the crash occurs, WHY if i set a non virtual base destructor and a virtual Derived destructor the crash happens...
Because that's the way the people who wrote the implementation you're using, chose to write it.
Undefined behaviour is undefined. Your program could crash. It could work fine. It could do something else. Anything is possible, because the standard says this undefined behaviour.
Often, compiler writers implement compilers in such a way as to optimize code that is legal, defined behaviour. Whatever happens when undefined behaviour occurs, usually happens as a consequence of the way they've done that optimized implementation.
We can't tell you why the code generated by your compiler crashes, because we're not the ones who wrote your compiler.
I don't understand why it would crash. When I test it on my own computer it doesn't crash. Do you use Visual C++ in debug mode by any chance? In that case maybe it's just some debugging code that catch that something is wrong and causes the program to crash? Do you get an error message, or error code? To really know what is going on you might have to study the assembly output.
It shouldn't crash, but the OP is being difficult. I've asked a number of questions and said quite a bit, but he/she doesn't seem to care and definitly doesn't answer my question, and just repeats the question "I don't understand ..., why is this happening ..."
delete takes a pointer. It doesn't know what type of object is pointed to,
gedamial wrote:
The object it points to is a Derived, which HAS a virtual destructor.
It's the Base that has NOT
Did you see where I said delete doesn't know what type of object is pointed to? It doesn't matter what (possibly derived) type it actually points to, all delete knows is you've given it a pointer-to-Base, and Base doesn't have a virtual destructor, so there is no reason for the compiler to invoke any destructor other than Base::~Base resulting in undefined behavior.
If you want to know what your compiler does specifically in this case where it is free to do absolutely anything at all, generate an assembly listing and inspect it. Of course that won't buy you much because behavior will probably change depending on the flags/settings you compile with or may even change with the addition of a random line of code.