2013-06-26 131 views
0

考虑下面的代码:了解删除C运营商++

#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 

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

也可以有人请解释delete如何工作。比如打电话new来电operator newconstructor,是delete操作类似?

感谢

+0

查看http://stackoverflow.com/questions/6441218/can-a-local-variables-memory-be-accessed-outside-its-scope/6445794#6445794 –

+0

更有趣:'int main(){ {tmp; } something_else(); }' - 假设由于缺乏副作用,内部块没有得到优化,无论如何.... – twalberg

回答

0

delete后称为fun1你到fun2电话是违法的。 C++不会握住你的手,因此对于这种“未定义的行为”,允许发生任何事情,包括正确调用fun2

其实delete调用对象的析构函数,然后释放内存,正好与new相反。

2

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

是的,这是不确定的行为,但因为没有实际上已经重新使用的内存也似乎到“工作” OK。这实际上是一个严重的错误。 (注意A::fun2()的定义永远不会去任何地方,那就是代码,而不是数据,所以对于程序的整个生命周期而言,存储位置ptr处的对象停止存在,但其成员函数的定义不存在。)

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

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

1

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

4

你在做什么在技术上是未定义的行为,所以真的,任何事情都可能发生,就标准而言。

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

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

这并不是说代码不坏。你的代码中永远不应该有未定义的行为。在较低的优化级别上,出于调试的目的,编译器可能会抛出对这类事情的检查,并通过错误消息来暂停程序或抛出异常。

0

当您致电delete时,操作系统会被告知不再需要此存储器,因此可用于未来分配。但是,它不会被自动擦除。

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

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来详细了解这一点。

0

成员函数在编译时解析。

你可以这样做:

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

只要这将作为你不访问数据存储中的对象(和它的虚函数表,所以你不希望调用方法做)。

'this'的值为null,并且可以。但重新排除任何内容都会导致段错误。