简体   繁体   中英

Understanding delete operator in C++

Consider below code:

#include <iostream>
#include <string>
 using namespace std;

class A{ 
 public: 
     int x; 
 public: 
     A(){x=0;} 
     void fun1(){ 
         cout << "fun1 is called \n"; 
         cout << "Address of this is " << this <<endl; 
         delete this; 
     } 
     void fun2() 
     { 
         cout << "fun2 called \n"; 
     } 
     ~A() 
     { 
             cout << "Object Destroyed" << endl; 
     } 
 }; 

 int main() 
 { 
     A* ptr=new A; 
     cout << "Address of ptr is " << ptr <<endl; 
     ptr->fun1(); 
     ptr->fun2(); 
     return(0); 
 }

The Output is:

$ ./TestCPP
Address of ptr is 0x20010318
fun1 is called
Address of this is 0x20010318
Object Destroyed
fun2 called

My question is that when we call delete in fun1() it destroys the object pointed by this pointer ie at address 0x20010318 . It calls the destructor as shown by output. Hence after calling fun1() the object at address 0x20010318 is destroyed and that memory is freed. Then why in the output we can see fun2() ? Is it just the garbage value ? I mean the object does not exist but at location pointed by ptr -> fun2() the definition of fun2() still exists?

Also can someone please explain how delete works. For instance calling new calls operator new and the constructor , is delete operation similar?

Thanks

What you are doing is technically undefined behavior, so really, anything can happen as far as the standard is concerned.

That aside, the actual behavior you are seeing can be easily reasoned about. fun2 is a non-virtual function. The compiler will resolve the call to it at compile time. When the object is destroyed, the function is not destroyed. And when you call ptr->fun2() , your compiler just calls the function. Since the function doesn't rely on any member data, the output is quite predictable (even though, as far as the standard is concerned, it's not).

Here's a demonstration of me calling a non-virtual member function on a null pointer. Clearly this is wrong, and yet it prints statement exactly as expected: http://ideone.com/pddnGt

This is not to say the code is not bad. You should never have undefined behavior in your code. On lower optimization levels, for debugging purposes, a compiler may very well throw in checks for this kind of thing and halt the program with an error message, or throw an exception.

Is it just the garbage value ? I mean the object does not exist but at location pointed by ptr -> fun2() the definition of fun2() still exists?

Yes, it's undefined behaviour, but because nothing has actually re-used the memory it seems to "work" OK. It's actually a serious bug though. (NB The definition of A::fun2() never goes anywhere, that is code, not data, so exists for the entire lifetime of the program, the object at the memory location ptr stops existing, but the definition of its member functions doesn't.)

For instance calling new calls operator new and the constructor , is delete operation similar?

Yes, it calls the destructor to destroy the object at that location then invokes operator delete to free the memory.

If your method isn't virtual and doesn't contain a reference to a member, it can works with some compilers as the method in assembly doesn't need a valid this pointer. Anyway, you must be carrefull with undefined behaviours.

After the delete is called in fun1 your call to fun2 is illegal. C++ doesn't hold your hands so for this "undefined behavior" anything is allowed to happen, including properly called fun2 .

In fact delete calls the object's destructor and then frees the memory, just the opposite of new .

When you call delete , the Operating System is informed that this memory no longer needed, and therefore available for future allocation. However, it will not be automatically wiped.

In your case, that memory is not used by anyone else before your call to fun2 . No one tried to allocate any memory in the heap in between the two function calls. Therefore, the object is still there and never tampered. However, it doesn't mean memory allocation is impossible in between the two calls (for example an interrupt may be triggered and memory may be allocated during processing of the interrupt). Therefore, you should never do this. :)

When you are calling a non-virtual function from a class, the function

class A { public: void function(int k) { ... } };

will be written as something like

void __A_function(A* this, int k);

If your function does not involve with this pointer, it will be called as a standard function, with this parameter neglected.

Another thing I can predict is, even you do like this

class A
{
private:
  int k;
public:
  A() : k(10) {}
  void function() { printf("%d\n",k); }
};

A* ptr=new A;
delete ptr;
ptr->function();

it will print out 10 in most cases. since the memory from new is not yet cleaned up.

I will recommend Inside C++ Object Model for a detailed understanding of this.

The member function are resolved at compile time.

You can do something like:

A* ptr = NULL;
ptr->yourFunc();

It will work as long as you don't access the data store in the object (and its VTable, so you don't want to call method).

The 'this' will have a value of null, and it will be OK. But derefenrencing anything will result in a segfault.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM