+5  A: 

Nothing. If you do this, then you get what you get. Don't do this.

Once you reassign p, you leak the Test object that p originally pointed at. You've now lost that memory for the duration of this app's runtime. Then when you delete a non-heap object, you're running into undefined behaviour and anything at all can happen (usually the runtime library will crash trying to delete non-heap memory - but you have no guarantees). There's absolutely nothing reliable that you can do once you've tried to delete non-heap memory.

You've already mentioned smart pointers, which is part of the solution. The other part is just being careful.

Eclipse
+17  A: 

You handle it by fixing the bug and recompiling your program. Anything else makes no sense.

Hans Passant
+9  A: 

You can't and you shouldn't try to deal with this situation other then not letting it occur in the first place.
There are some basic rules in C++ that simply have to be obeyed.

Georg Fritzsche
+4  A: 

Unfortunately there's nothing you can do. The C++ compiler can't tell from your code whether or not you might delete a pointer in the future, so you have to be sure to manage them correctly in your code. This means that if you put the address of a non-heap-allocated item into a pointer, it's your responsibility nto to delete that pointer.

In short, C++ can't protect you from every possible mistake you can write.

Mark B
+1  A: 

You need to swap the assignment and delete statements:

 delete p;
 p = &global;

BUT I would suggest never using the same variable to point at data that requires an explicit free and data that does not. Pick one or the other for each variable, so you can either always delete the memory before reassigning it or never delete it. If you try to keep track of how you're pointers got set, you'll wind up spending all your time whining about how C++ provides no memory management and forces you to write unmaintainable code.

John Gordon
Davit Siradeghyan
A: 

It is possible to overload delete. In theory you could have your overloaded delete refuse to do anything unless the address is valid. But how do you know if it's valid? The best you can say is "this wasn't allocated with new," but you'll probably have to overload new to do that.

For the record, the standard new and delete crash in this case because delete determines the address didn't come from new and assumes the worst. Assuming the worst is probably the best thing to do in that situation, though; at least it beats assuming the best.

So I'll second the advice to not protect against this in code, and simply don't do that.

Max Lybbert
unfortunately, there's no guarantee of a crash.
peterchen
+1  A: 

The primary way to avoid this is to simply avoid using new or delete under any but the most tightly controlled circumstances.

Using new inside of main is particularly suspect -- the reason to use new in C++ is when you need to create an object that needs to outlive the scope in which it's being created (e.g., when you reach the end of that function, it must not be destroyed). In the case of main, the only reason to do what would be if you were allocating something in main that would not be deleted in main, but used by some the destructor of some global object as it ran after you returned from main (which is rarely done and even more rarely a good idea).

Most uses of new should be in the ctor of an object, and most uses of delete should be in the dtor of an object. If you have something like a collection, it can also make sense to use new and/or delete in some other member function(s) that handle(s) things like re-sizing the collection.

Other than that, there are entity objects that generally aren't ever assigned or copied. For example, consider a call routing system, where you create a "call" object when somebody dials their phone, and you destroy the object when they hang up. In nearly every such case, you have a global collection (or more than one) that holds pointers to these objects, so as soon as you create the object, its address goes into the (correct) global collection. Interesting point: nearly all code that I've seen where this pattern made sense did not have any external code that destroyed the object -- rather, the object itself was responsible for removing itself from the global connection, and using the (much argued-about) delete this; to destroy itself when the real-world connection (or whatever) it was attached to ended.

Jerry Coffin
+1  A: 

You can use the code below to find out if a pointer points to a stack area or heap area:

bool IsMemoryOnStack( void* p )
{
    void* dwStackTop = 0;
    void* dwStackLowCurrent = 0;
    __asm  {
        mov EAX, FS:[4]
        mov dwStackTop, eax
            mov EAX, FS:[8]
            mov dwStackLowCurrent, eax
    }

    return ( p<= dwStackTop && p>= dwStackLowCurrent );
}
Sherwood Hu