大家好:
请先看这段代码!
///////////////////////////////////////
type
class1=class
field1:Integer;
end;var
obj1:class1;
begin
obj1:=class1.create;
obj1.field1:=11;
obj1.desctory;
//obj1.free; //这里使用过,和上面的效果一样
if obj1=nil then
begin
writeln('对象释放后为空指针!');
end
else
begin
writeln('对象释放后不是空指针!');
end;
obj1.field1:=12;
writeln(obj1.field1); //对象分别用free和destory释放,结果仍然可以访问!
readln;
end.
///////////////////////////////////////
大家应该明白我的问题了:为什么一个对象释放以后,仍然可以访问??? 那么,应该如何真正释放掉一个对象呢?谢谢!
请先看这段代码!
///////////////////////////////////////
type
class1=class
field1:Integer;
end;var
obj1:class1;
begin
obj1:=class1.create;
obj1.field1:=11;
obj1.desctory;
//obj1.free; //这里使用过,和上面的效果一样
if obj1=nil then
begin
writeln('对象释放后为空指针!');
end
else
begin
writeln('对象释放后不是空指针!');
end;
obj1.field1:=12;
writeln(obj1.field1); //对象分别用free和destory释放,结果仍然可以访问!
readln;
end.
///////////////////////////////////////
大家应该明白我的问题了:为什么一个对象释放以后,仍然可以访问??? 那么,应该如何真正释放掉一个对象呢?谢谢!
解决方案 »
- delphi Ado操作 表字段为整型
- 对于一组动态生成的控件如何获得当前活动控件的名字
- 关于求日期的问题
- 建有一QQ群2044725.为Delphi志同道合的朋友提供个交流空间,有兴趣的可以进来交流,此群为永久固定群,还有15个空位
- 断点调试失效!请高人指点.
- 关于OLE拖拽(原创)(参考了MSDN上一些信息)
- 请教各位!ShowMessage()和MessageDlg()与MessageBox()它们之间有何区别??
- 看看这句SQL这样写有什么毛病?简单的SQL
- 急,急,急,dbgirdeh自动适应列宽,数据显示慢!
- Delphi 7 中使用IdUDPServer1和IdUDPClient1控件实现通信检测
- 大家都用什么作版本控制?
- 线程的问题
将你的代码做简单的修改:var
obj1:class1;
obj2:class1;
begin
obj1:=class1.create;
obj1.field1:=11;
obj1.Free; if obj1=nil then
begin
showmessage('对象释放后为空指针!');
end
else
begin
showmessage('对象释放后不是空指针!');
end;
obj1.field1:=12;
obj2:=class1.create;
obj2.field1 := 99;
showmessage(inttostr(obj1.field1)); //对象分别用free和destory释放,结果仍然可以访问!增加了一个obj2对象,并且在显示obj1.field1前创建了一个obj2的实例,将field1设置为99。可以看到obj1.field1变成99了,这就是:obj1占用的内存被释放并且被obj2使用了,但是obj1的引用还是指向原来自己占用的内存块,这就出现了obj1和obj2指向同一个内存块的情况。所以你在使用了一个对象后Free后还要将对象设置为nil。
但是,这只是实现中存在的一个副作用,并不包括在语言的定义中。在创建前或释放后访问对象的field都是对悬空地址的访问,只是由于现在的实现,使它恰好等于原有对象的地址,但这个空间是已经释放的,对这块空间的使用是非法的。
另外object释放后,对象引用不会变为nil,只是变为悬空引用,需要自己将它赋为nil。
var
obj1,obj2:class1;
begin
obj1:=class1.create;
obj1.field1:=11;
ShowMessage(inttostr(obj1.field1));
obj1.destroy;
if obj1=nil then
begin
ShowMessage('对象释放后为空指针!');
end
else
begin
ShowMessage('对象释放后不是空指针!');
end;
obj2:=class1.Create;
obj1.field1:=12; ***********关键在这里1**********
ShowMessage(inttostr(obj1.field1));
ShowMessage(inttostr(obj2.field1)); ***********关键在这里2**********
运行的结果,在2处,obj2.field1 居然是12 ?
why ?
因为,在 obj1,obj2:class1;处,声明对象的时候,只是为obj1和obj2分配了
32bit的空间,此时,该空间的内容是无意义的,只有在obj1:=class1.create;之后,
系统为obj1按照class1的定义,分配了相应的内存区域,并把obj1指向该空间。可以说,obj1的
自己的32bit空间里存的是该内存区域的指针。
当obj1.destroy之后,系统只是收回
分配的内存区域(讲该区域设为空闲),此时,虽然obj1的值没变,但是,所指向的内存区域已经被系统回收了。
正是因为这样,在obj2:=class1.Create;处,系统又从空闲空间中取出一段区域,分配给obj2。由于obj1的空间
刚刚被释放,所以又把该段空间分配给了obj2,这就相当于obj1和obj2所指向的内存区域是同一块。所以,
obj1.field1:=12; 也就改写了obj2.field1。本质上,obj1和obj2的内容(32bit的指针值)是相同的。
楼主的问题的实质,只不过是系统回收了一段空间,但并未把指向该空间的指针置空。这样,就留下了可以通过该指针
访问不该访问的空间的问题。
一家之言,难免错误百出,恳请各位不吝赐教。