我的问题是,如何检查对象是否已被破坏?除了Assigned()之外,还有什么可以检查该对象是否仍然存在?
program Project1;
uses System.SysUtils;
type TObj = class
public
Name: string;
end;
var AnObj, AnObj2 : TObj;
begin
try
try
AnObj := TObj.Create;
AnObj.Name := 'Testing';
AnObj2 := AnObj; // AnObj passed to other procedures as param
FreeAndNil(AnObj2); // somewhere else "Free" the object out of my control
// as a result, AnObj is still assigned but the object is destroyed
finally
if Assigned(AnObj) then // AnObj is assigned, HOW COULD I IMPROVE HERE?
FreeAndNil(AnObj); // Exception: Invalid pointer operation
end;
except
on E:Exception do
writeln(E.Message);
end;
readln;
end.
答案 0 :(得分:4)
如何检查对象是否已被破坏?
简短的答案是您不能做到。没有任何机制可以让您在手动内存管理下检查对象的有效性。
如果要出于调试目的跟踪有效性,则可以使用自定义内存管理器(如处于完全调试模式的FastMM),该跟踪器可以跟踪所有引用,并在访问悬空指针时进行报告。
FreeAndNil
与Assigned
结合使用仅在对对象具有单个引用时才有效。如果您有更多引用,它会崩溃,因为FreeAndNil
只能nil
引用您引用的引用。所有其他引用将变为悬空指针,Assigned
无法检测到悬空指针。
简而言之,Assigned
仅在引用指向有效对象实例或包含nil
值时起作用。在手动内存管理下,如果您需要使用Assigned
,则必须保持跟踪并确保引用始终包含有效值。
在对对象保持单一引用时使用Assigned
如果您具有对对象的单一引用,则可以将Assigned
用于惰性初始化模式,如果尚未创建对象实例,则可以在其中创建对象实例。但是您必须确保对象引用首先包含nil
引用。
仅当对象引用是类字段,对象实例字段或全局变量时,它们才会自动初始化为nil
。
如果您不打算在释放该对象引用后再使用它,则可以使用Free
释放其内存。
如果您具有可重复使用的引用,则要在其中多次创建和释放对象实例,则必须使用FreeAndNil
,或在调用Free
之后将引用设置为nil。这是确保对象释放后Assigned
可以工作的唯一方法。同样,仅当您保留对该对象的一个引用且只有一个引用时,此Assigned/FreeAndNil
模式才有效。
在保留对一个对象的多个引用时使用Assigned
如果可能,请不要对一个对象实例保留多个引用。如果您确实必须对一个对象实例保留多个引用,则需要实现某种机制以确保您可以通知所有引用该对象不再有效。
有几种方法可以做到:
TComponent
作为基类-当对象实例将被销毁时,您可以在其中使用其通知系统来获取通知 注意:对于2和3.,您必须手动nil
对对象的所有引用,直到它们收到通知将被销毁的通知。如果不这样做,则未设置为nil
的任何引用都将无效,如果悬停引用使用Assigned
的任何引用,将无法正常工作。
如果遇到将对象作为参数传递的情况,并且在该对象上有一些超出控制范围的代码称为Free
,那么您正在处理所有权转移。您创建了对象,但是随后将所有权(发布对象的责任)转移到了其他一些代码。之后,您不应再使用该对象引用(在某些狭窄的情况下,除非确定传输完成后的即时代码不会触发对象释放)。
仅当有某种通知机制(如前所述)可以在对象实例释放时通知您时,才可以使用不拥有的对象引用(在转让所有权之后)。
此外,您永远都不要释放您不拥有的对象。在您的示例中,即使可以通知您对象将被破坏,您所能做的就是nil
指向该对象的引用。您不应该尝试释放它。