0

考虑下面的代码:

#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); 
 }

输出是:

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

我的问题是,当我们调用它时deletefun1()它会破坏this指针指向的对象,即地址0x20010318。它调用析构函数,如输出所示。因此,fun1()在地址处调用对象后被0x20010318销毁并释放内存。那么为什么在输出中我们可以看到fun2()呢?它只是垃圾值吗?我的意思是该对象不存在但在ptr -> fun2()定义所指向的位置fun2()仍然存在?

也有人可以解释一下是如何delete工作的。比如调用newcallsoperator newconstructor,delete操作类似吗?

谢谢

4

7 回答 7

4

您正在做的是技术上未定义的行为,所以实际上,就标准而言,任何事情都可能发生。

除此之外,您所看到的实际行为可以很容易地推断出来。fun2是一个非虚函数。编译器将在编译时解析对它的调用。当对象被销毁时,函数不会被销毁。当您调用时ptr->fun2(),您的编译器只会调用该函数。由于该函数不依赖任何成员数据,因此输出是完全可预测的(尽管就标准而言,它不是)。

这是我在空指针上调用非虚拟成员函数的演示。显然这是错误的,但它完全按照预期打印语句:http: //ideone.com/pddnGt

这并不是说代码还不错。您的代码中不应该有未定义的行为。在较低的优化级别上,出于调试目的,编译器很可能会检查此类事情并使用错误消息暂停程序,或抛出异常。

于 2013-06-26T16:00:19.603 回答
2

它只是垃圾值吗?我的意思是该对象不存在但在ptr -> fun2()定义所指向的位置fun2()仍然存在?

是的,这是未定义的行为,但是因为实际上没有任何东西重新使用了内存,所以它似乎“工作”了。虽然它实际上是一个严重的错误。(注意,A::fun2()从不去任何地方的定义,即代码,而不是数据,因此在程序的整个生命周期中都存在,内存位置的对象ptr停止存在,但其成员函数的定义不存在。)

比如调用new调用operator new和构造函数,delete操作类似吗?

是的,它调用析构函数来销毁该位置的对象,然后调用operator delete以释放内存。

于 2013-06-26T15:58:22.537 回答
1

如果您的方法不是虚拟的并且不包含对成员的引用,则它可以与某些编译器一起使用,因为汇编中的方法不需要有效的 this 指针。无论如何,您必须小心对待未定义的行为。

于 2013-06-26T16:00:01.893 回答
0

在你的调用delete中调用之后是非法的。C++ 不会牵你的手,因此对于这种“未定义的行为”,任何事情都可以发生,包括正确调用的 .fun1fun2fun2

实际上delete调用对象的析构函数然后释放内存,与new.

于 2013-06-26T15:58:07.343 回答
0

成员函数在编译时解析。

您可以执行以下操作:

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

只要您不访问对象中的数据存储(及其 VTable,因此您不想调用方法),它就会起作用。

'this' 的值为 null,并且没问题。但是取消引用任何内容都会导致段错误。

于 2013-06-27T08:36:15.880 回答
0

当你从一个类中调用一个非虚函数时,这个函数

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

将被写成类似

void __A_function(A* this, int k);

如果您的函数不涉及this指针,它将作为标准函数调用,this忽略参数。

我可以预测的另一件事是,即使你这样做

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

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

在大多数情况下,它会打印出 10 个。因为内存new尚未清理。

我将推荐 Inside C++ Object Model 来详细了解这一点。

于 2013-06-26T17:02:21.330 回答
0

当您调用delete时,操作系统会被告知不再需要此内存,因此可用于将来的分配。但是,它不会被自动擦除。

在您的情况下,在您调用fun2. 没有人试图在两个函数调用之间分配堆中的任何内存。因此,对象仍然存在并且从未被篡改。但是,这并不意味着在两次调用之间不可能分配内存(例如,可能会触发中断,并且可能会在处理中断期间分配内存)。因此,您永远不应该这样做。:)

于 2013-06-26T16:02:44.080 回答