李战:
不管有没有垃圾回收,构造函数与析构函数中的异常处理不好都可能导致孤魂野鬼
[阅读: 831] 2007-01-12 03:40:53
一般来说,当构造一个对象时,会对没一个类层次的构造和析构函数对嵌套一层try...except...end的结构。
类似于这样的代码:
class1.create
try
class2.create
try
....
except
class2.destroy;
raise;
end;
except
class1.destroy;
raise;
end;
从这些代码可以看出,当一个层次的构造函数完全成功后,能保证在构造其他层发生异常时调用已构造层的析构函数。因此,如果在当前层的构造函数已分配资源,并且在本层构造完成前发生异常,你应该自己释放资源,而不能让构造机制去处理,因为它处理不了。
严格的说,在每一个构造函数内都应该写成这样的形式:
constructor TClass1.Create;
begin
//嵌套构造前分配资源
Resource1 := TResource1.Create;
try
inherited Create; //嵌套上层构造函数
...
//嵌套构造后分配资源
Resource2 := TResource2.Create;
try
...
except
Resource2.Destroy;
raise;
end;
except
Resource1.Destroy;
raise;
end;
end;
如果不这样写,就有可能产生内存垃圾。
反过来,而对象析构的过程大都只是简单地调用每一层的析构函数,没有任何异常保护。因此,在析构函数中产生的异常将不再调用上层的析构函数,更容易产生内存垃圾。严格地说,你因该解决析构函数中的所有异常,不能对外抛出。
为什么很多主要也无代码都写得很严谨的程序还是会出现内存泄露?结果发现,大多数是构造和析构代码不严谨。
因此,很多优秀的程序员在一直牢记这么一条原则“构造中一定要处理异常,析构时一定不要抛出异常”!
很遗憾,垃圾回收机制并不能帮助你解决这一问题。垃圾回收机制的确能让我们少操心对象的生死,它就像传说中的阎王爷。每当一个对象投胎时,就在它的生死簿上记上一笔,而这个对象老去时,它就来招对象的魂。不过,它也处理不了在投胎和招魂时发生的异常情况。否则,世间哪来这么多的孤魂野鬼?
程序员优秀不优秀,关键看编程习惯...
李战(leadzen) 2007.1.12 深圳
李战(leadzen)