对象的delete都在什么时候?
qiezi
2007-04-20
的确是跑题了,我验证了一下觉得应该是没有调用,原因是该对象是全局变量。
这个问题涉及到全局变量初始化和释放顺序问题,由于这些顺序并不能完全由编译器推断出来,所以可能造成析构出错,于是它干脆不析构。 |
|
player7
2007-04-20
谢谢了,看来还是老老实实写一大堆 delete 吧。。。
感觉智能的东西也是很危险的。。。 |
|
qiezi
2007-04-20
有个简单的办法让它一定析构:
Foo foo; // 全局变量 static ~this() { delete foo; } 主要原因可能是它无法推断出析构顺序,所以你需要这样去显式析构。 全局变量在很多有GC的语言里都禁止使用的,D里面只是允许,但各种场合都应该避免使用。 |
|
achun
2007-04-20
这是我来的这个圈子里
我看到的最有价值的帖子了. 全局变量的安全销毁. 应该写入D语法军规了. |
|
oldrev
2007-04-20
把全部代码贴出来看看,是不是析构有循环依赖?
我个人的最佳实践是: 1. 只持有GC内存的对象让GC处理就行了,scope 是留给异常发生时处理时用的,要是到处都是scope(exit)delete x;还要GC干什么? 2. 持有非GC内存资源的对象应该添加一个形如 close() 的显式析构函数,客户程序最好手动调用它。为了防止客户程序忘记调用close,应该在 ~this() 里调用 close() 形成双保险。 |
|
qiezi
2007-04-20
实际上是全局对象的析构问题。
|
|
player7
2007-04-20
我用“全局对象的析构问题”搜了一下百度,发现这样的问题还真不少。
在CSDN上就有这个: http://cache.baidu.com/c?word=%C8%AB%BE%D6%3B%B6%D4%CF%F3%3B%B5%C4%3B%CE%F6%3B%B9%B9%3B%CE%CA%CC%E2&url=http%3A//topic%2Ecsdn%2Enet/t/20050705/11/4123659%2Ehtml&p=8361ce0297934ea959bcc7710e1cc6&user=baidu 我按他的程序用D写了一遍,出现同样的问题: class Foo { this(){ printf( "before main()\n"); } ~this(){ printf( "after main()\n"); } }; Foo sf; void main() { sf=new Foo; printf( "Hello, world!\n"); } [\code] 但是,他们讨论的结果有点不同, ///////////// 也就是说 cout有可能在 smallFoo的析构函数 被调用之前就已被析购了 所以无法输出 ///////////// 他们认为析购是成功了,但是输出函数不起作用,所以看不到显示。 |
|
qiezi
2007-04-20
C++的情况不要拿过来类比,没有意义。另外如果全局对象析构导致这么多未定义行为,根本就应该避免使用,可以想象如果要使用得多么小心,这有什么意义呢?
我前面给出的static ~this里面调用delete就可以看出来,即便是对象真的会析构,也必定是在module的析构以后,这时候真的没什么意义了,因为这时已经没什么可以做的了。 下面是实际执行的代码: result = main(args); _moduleDtor(); gc_term(); 在moduleDtor后面就是gc_term,它所能帮的就是一次的GC。但这个时候全局对象依旧被引用,GC也没能释放它。 为了验证我这个说法,你可以尝试在程序退出前把全局变量赋值为null,这时对象并没有被析构。然后gc_term执行一次完全GC,对象就可以释放掉了。代码如下: import std.stdio; class Foo { this(){writefln("Foo\n");} ~this(){ writefln("~Foo\n"); } } Foo foo; void main() { foo = new Foo; foo = null; // <== LINE A writefln("end"); } 你可以试试注释掉LINE A,观察结果有什么不同。 |
|
oldrev
2007-04-20
C++ 的cout是全局对象,它很可能在你的全局对象析构之前就销毁了,因此没有输出。
|
|
oldrev
2007-04-20
Effective C++ 里有一条专门讲这个,你无法知道全局对象的构造和销毁顺序,不要依赖他们
...待续 |