0
#include <iostream>
#include<stdio.h>

using namespace std;

class aaa{

public:
    void methodTest(){

        cout << "line1\n";
        cout << "line2\n";
        cout << "line3\n";

        delete this;

        cout << "line4\n";
        cout << "line5\n";
        cout << "line6\n";
        cout << "line7\n";
        cout << "line8\n";

    }
    virtual ~aaa(){
        cout <<"destrcutor aaa\n";
    }
};


int main(int argc, char**argv) {


    aaa* ptr = new aaa();
    cout <<"============first  time==============\n";
    ptr->methodTest();
    cout <<"============second time==============\n";
    ptr->methodTest();

    return 0;
}

Output

============first  time==============
line1
line2
line3
destrcutor aaa
line4
line5
line6
line7
line8
============second time==============
line1
line2
line3

RUN FINISHED; Segmentation fault; core dumped; real time: 70ms; user: 0ms; system: 0ms

My question is why we can run ptr->methodTest() at second time ? It should coredump when calling ptr->methodTest() at second time immediately right ? why it still be able to run until reach "delete this"

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Denny
  • 449
  • 4
  • 17
  • You can use the pointer to an object after it has been `delete`d but in very limited circumstances. Most of the time this yields UB. In your code, what caused the segmentation fault was the fact that you deleted the pointer twice. – Cassio Neri Sep 13 '13 at 10:56

6 Answers6

3

My question is why we can run ptr->methodTest() at second time ?

It's undefined behaviour. The error can't be prevented by a compile-time check, since the compiler can't in general track the run-time lifetime of objects, and C++ usually doesn't impose the overhead of run-time checks.

It should coredump when calling ptr->methodTest() at second time immediately right ?

You might get a protection fault when the pointer is accessed. Simply calling a non-virtual member function typically doesn't access the object, so the error is likely to go undetected at that point. (And that's assuming that the memory is no longer accessible; in practice, the pointer will often still point to accessible memory, so even attempting to access the deleted object might go undetected).

Mike Seymour
  • 249,747
  • 28
  • 448
  • 644
2

All non-virtual member functions can be thought of this way:

object->mfun(args...)

is equivalent to:

mfun(object, args...)

With me so far? Ok. Now, when calling ptr->method_test(), you can consider yourself to be calling method_test(ptr). As you can see, no pointer is actually dereferenced in that invocation. This means that the program continues doing what it does until something like deleting a pointer that was already deleted happens. Calling a virtual function would trigger a crash too.

Do bear in mind, though, that this is just how a "typical" implementation operates. It's all undefined behaviour and may launch the nukes instead of appearing to work for a little while.

Kaz Dragon
  • 6,681
  • 2
  • 36
  • 45
1

It is undefined behaviour to access an element after it has been deleted.

You just got lucky.

RedX
  • 14,749
  • 1
  • 53
  • 76
  • 2
    Or unlucky. Apparently, he has enough sense to recognize that a program crash here would be the best thing he could get. – James Kanze Sep 13 '13 at 11:08
  • Well, you could say lucky in the sense that the UB _seems_ to not have caused any damage in this case . – Hulk Sep 13 '13 at 11:20
1

Because Undefined Behavior is - well, undefined. Anything at all could happen. Compilers are free to optimize code containing UB to do pretty much anything they want, including not doing anything at all, doing exactly what you expect it to do 99,9% of the time and catching you years later when you've completely forgotten about it.

It could also decide to format your hard disk or make your PC join a botnet ;-)

See e.g. What Every C Programmer Should Know About Undefined Behavior and the anecdotes in this question

Community
  • 1
  • 1
Hulk
  • 6,399
  • 1
  • 30
  • 52
0

Deleting a pointer in release does not clear the memory area to which it pointed, it just marks the area as free. Technically in release the area still contains all the data for your class. You can still call methods on this pointer but you end up with a dangling pointer. Typically you can call methods that do not involve members which may or may not run as it is undefined behaviour. In debug many compilers mark the freed area with magic values like 0xFEEEFEEE to be easily distinguished when debugging.

Typically when working with pointers I would suggest setting the pointer to nullptr after deleting it to avoid dangling pointer

Samuel
  • 6,126
  • 35
  • 70
  • Deleting a pointer make do anything it wants with the underlying memory. I know I have an implementation which "resets" the deleted memory, and I believe that the Microsoft delete in `MDd` does as well. – James Kanze Sep 13 '13 at 11:02
  • And setting the pointer to `nullptr` doesn't really solve anything. (He can't do it here anyway, since `this` can't be assigned to.) – James Kanze Sep 13 '13 at 11:03
  • Don't get me wrong. As I stated in release freed memory is rarely reassigned as this will cost performance. In debug however as stated many debuggers use magic values to indicate the deleted memory for ease of debugging. Deleting this is also something you don't do most of the time. – Samuel Sep 13 '13 at 11:07
  • @Samuel "Deleting `this` is also something you don't do most of the time": this clearly depends on the application, because I find that `delete this` is probably the most frequent delete in application code. (But this certainly depends on the application.) – James Kanze Sep 13 '13 at 11:10
  • Can you name some examples? In my opinion the creator should be responsible for deletion as the responsibility should be clear. – Samuel Sep 13 '13 at 11:30
0

Well, since the method itself is just a piece of assembly code that get the class instance pointer, it can be executed and in fact, if it would not do anything (e.g. just an empty body) it would not even crash, since you are not referencing any invalid memory addresses, the crash happens when you start to reference some member variables of the deleted instance, since that memory has already been freed.

Rudolfs Bundulis
  • 11,636
  • 6
  • 33
  • 71