Delete calling destructor but not deleting object?

So I have been working with c++ and pointers for a year and a half now, and i thought i had them succeed. I have called delete on objects many times before and the objects actually got deleted, or at least i thought they did.

The code below is just confusing the hell out of me:

#include <iostream>

class MyClass
{
public:
    int a;

    MyClass() : a(10) {
        std::cout << "constructor ran\n";
    }

    void method(std::string input_) {
        std::cout << param_ << "\n";
    }

    ~MyClass() {
        std::cout << "destructor ran\n";
    }

};

int main()
{

   MyClass* ptr = new MyClass;

   ptr->method("1");

   delete ptr;

   ptr->method("2.5");

}

this code outputs:

constructor ran
1
destructor ran
2.5

I was confused as to why it was not throwing an error of any sort - I was expecting a memory out of bounds exception or alike, but nothing. The for loop was in there incase there was some sort of hidden garbage collection, even though as far as I know there is no garbage collection in c++.

Can anyone explain as to why this code works, or where I am going wrong with this code for it not to give me the error?


Solution 1:

You're misunderstanding what delete does. All delete does is call the destructor, and tell the allocator that that memory is free. It doesn't change the actual pointer. Anything beyond that is undefined.

In this case, it does nothing to the actual data pointed to. That pointer points to the same data it pointed to before, and calling methods on it works just fine. However, this behavior is not guaranteed; in fact, it's explicitly unspecified. delete could zero out the data; or the allocator could allocate that same memory for something else, or the compiler could just refuse to compile this.

C++ allows you to do many unsafe things, in the interest of performance. This is one of them. If you want to avoid this kind of mistake, it's a good idea to do:

delete ptr;
ptr = NULL;

to ensure that you don't try to reuse the pointer, and will crash immediately if you do rather than having undefined behavior.

Solution 2:

Calling ptr->method("2.5") after delete ptr has undefined behaviour. This means anything can happen, including what you're observing.

Solution 3:

In this code:

MyClass* ptr = new MyClass;
ptr->method("1");
delete ptr;
ptr->method("2.5");

you are accessing the memory that has already been freed, which yields undefined behavior, which means that anything can happen including the worst case: that it seems to work correctly.

That's one of the reasons why it is a good practice to set such a pointer to NULL rather than allowing this kind of stuff happen:

delete ptr;
ptr = NULL;

although the best thing to do is to completely avoid using pointers if possible.