I\'m new to C++ and from what I learned so far when you call delete on a pointer that points to something created on the heap then whatever is pointed by that pointer gets e
So, my question is, why I'm still able to call Go_XXX_Your_Self() and Identify_Your_Self() even after the object was deleted?
Because of undefined behavior.
Is this how it works in C++? (is there even after you delete it?)
Because of undefined behavior. There is no guarantee that it will work the same on other implementations. Again, undefined behavior.
Also can you check to see if it's not there? (I know theoretically is not possible but I'm curious to see what methods are out there)
delete MC1;
MC1 = nullptr;
By setting the pointer to nullptr
after delete
ing it, the runtime is most likely to detect that you are accessing an invalid, you-have-no-right-to-use location. Also, by diligently doing this for all applicable pointers, you have the ability to check if the object is valid or not (valid if non-nullptr
).
if(my_ptr) {
// my_ptr is most possibly valid (though you can still go wrong)
// use my_ptr
}
Similarly, you should also set raw pointers to nullptr
when they aren't yet initialized to some valid address.
MyClass* some_ptr = nullptr;
...
But again, if you have access to modern C++11 facilities, it's much better not to use raw pointers at all, and just use std::unique_ptr
or std::shared_ptr
(depending on your required semantics). And on future C++ standard revisions, you may also want to use the proposed std::exempt_ptr which is a non-owning, observe-only pointer wrapper.
The C++ compiler will not typically generate code to check the validity of your pointers on your behalf. If you care, you need to provide the code yourself. Since accessing freed memory invokes undefined behavior, the outcome of doing so is non-deterministic.
You should not be manipulating raw pointers anyway, and instead rely on one of the smart pointers for you. Then, you are much less likely to run into this error, since you will rely on the pointer falling out of scope to allow the memory to be destructed.
However, even so, you may still run into cases where you force bad things to happen, for example:
std::unique_ptr<Foo> p(new Foo);
p->foo();
p.reset(0);
p->foo();
You can try to catch such problems at runtime with a smart pointer wrapper that does some form of checking for you:
template <typename T>
class CheckedSharedPtr {
std::shared_ptr<T> ptr_;
public:
//...
T * operator -> () const {
if (ptr_ == 0) {
//...throw something
}
return ptr_.operator->();
}
};
But, this just adds extra overhead to each and every pointer access. The better method is to utilize a good static code analysis tool that can help identify these kinds of problems in your code, along with many others.
The mechanics are that delete simply tells the system that the memory is no longer needed and can be repurposed for use again. There is no other action taken. This is the basis of the use-after-free errors seen in security disclosures. It is contingent on the programmer to not use the memory again.
To that end, RAII is one method to attempt to reduce incidents of this problem.
When you call delete
on an object, the memory used by that object is made available to use by another use of new
(or, really, by anything that uses the heap). Until such time, the deleted object may (or may not) retain its previous value. But eventually, as your program goes on running, the memory used by the deleted object will be overwritten, and then bad things will happen if you're lucky: your program will crash on you. If you're unlucky, you program will not crash until it is deployed in the field.
You were unlucky. The memory hadn't been written over yet, and things still acted normally.
Some other time you might get lucky and you'll crash hard, which will highlight the problem.
Accessing memory that you've delete
d isn't something you should ever do. In C++, it's up to you not to do that, because the compiler won't stop you.