请考虑以下代码:
#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
我的问题是,当我们在delete
中调用fun1()
时,它会破坏this
指针指向的对象,即地址0x20010318
。它调用析构函数,如输出所示。因此,在调用fun1()
之后,地址0x20010318
处的对象被销毁并且该内存被释放。那么为什么在输出中我们可以看到fun2()
?这只是垃圾价值吗?我的意思是对象不存在,但在ptr -> fun2()
指向的位置fun2()
的定义仍然存在?
也可以请某人解释delete
的工作原理。例如,调用new
调用operator new
和constructor
,delete
操作是否类似?
由于
答案 0 :(得分:4)
您所做的是技术上未定义的行为,因此,就标准而言,任何事情都可能发生。
除此之外,您所看到的实际行为很容易被推理。 fun2
是非虚函数。编译器将在编译时解析对它的调用。当对象被销毁时,该功能不会被破坏。当你调用ptr->fun2()
时,你的编译器就会调用该函数。由于该函数不依赖于任何成员数据,因此输出是可预测的(尽管就标准而言,它并非如此)。
这是我在空指针上调用非虚成员函数的演示。显然这是错误的,但它会完全按预期打印语句:http://ideone.com/pddnGt
这并不是说代码也不错。您的代码中永远不应该有未定义的行为。在较低的优化级别上,出于调试目的,编译器可能会很好地检查此类事情并使用错误消息暂停程序,或者抛出异常。
答案 1 :(得分:2)
这只是垃圾值吗?我的意思是对象不存在,但在
ptr -> fun2()
指向的位置fun2()
的定义仍然存在?
是的,它是未定义的行为,但因为没有任何实际重新使用内存,它似乎“工作”好。这实际上是一个严重的错误。 (NB A::fun2()
的定义永远不会去任何地方,即代码,而不是数据,因此存在于程序的整个生命周期中,内存位置ptr
处的对象停止存在,但其定义为成员函数没有。)
例如调用
new
调用operator new
和构造函数,delete
操作是否类似?
是的,它调用析构函数来销毁该位置的对象,然后调用operator delete
来释放内存。
答案 2 :(得分:1)
如果您的方法不是虚拟的并且不包含对成员的引用,则它可以与某些编译器一起使用,因为程序集中的方法不需要有效的this指针。 无论如何,你必须对未定义的行为充满信心。
答案 3 :(得分:0)
在delete
中调用fun1
后,您对fun2
的通话是非法的。 C ++不会牵着你的手,所以对于这种“未定义的行为”,任何事情都可以发生,包括正确调用fun2
。
实际上delete
调用对象的析构函数,然后释放内存,与new
相反。
答案 4 :(得分:0)
当您致电delete
时,系统会通知操作系统不再需要此内存,因此可供将来分配。但是,它不会被自动擦除。
在您的情况下,在致电fun2
之前,其他人不会使用该内存。没有人试图在两个函数调用之间分配堆中的任何内存。因此,物体仍然在那里,永远不会被篡改。然而,这并不意味着在两次调用之间不可能进行存储器分配(例如,可以触发中断并且可以在处理中断期间分配存储器)。因此,你永远不应该这样做。 :)
答案 5 :(得分: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 ++对象模型来详细了解这一点。
答案 6 :(得分:0)
成员函数在编译时解析。
您可以执行以下操作:
A* ptr = NULL;
ptr->yourFunc();
只要您不访问对象中的数据存储(及其VTable,因此您不想调用方法),它就会起作用。
'this'的值为null,就可以了。但是,对任何事情进行解体都会导致段错误。