​这里​

按​​GC​​拥有​​对象​​构造​​类对象​​来,写这些.

准则:

论坛中看到了以下几个观点.

1,(这是复杂问题.)类没有​​析构器​​;应该叫​​终结者​​.

2,不要在​​类析构器​​中从​​GC​​分配内存.(如,​​writeln​​可能适合​​简单类型​​,但​​writefln​​或​​format​​则不行.)

3,因为可能​​已析构​​,不要​​使用​​类析构器中​​GC​​拥有​​成员​​.

一些事实:

1,​​不保证​​执行​​类析构器​​.这是程序员无法控制的.如,用户可​​传递​​以下​​命令行选项​​,而​​GC​​不会执行类析构器:

$ myprogram "--DRT-gcopt=cleanup:none" ...

(这样启动时,以下​​示例​​运行良好.)

2,即使​​GC​​执行了​​析构器​​的,也不知道​​何时​​准确执行.因此,重要任务交给​​类析构器​​(如​​关闭​​文件)是​​不行​​的.

恐怖:

我刚刚发现​​一个​​大问题.

上面​​两个准则​​(“不要​​使用​​类成员"和"不要​​分配​​”)错过重要的事实,对类​​结构成员​​也要递归这样.如,作为​​类成员​​的​​结构​​也不能在​​析构器​​中​​分配​​内存.

以下程序以​​core.exception.InvalidMemoryOperationError​​结束:

import std.format;

void closeConnection(string s) {
}

struct S {
int id;

~this() {
closeConnection(format!"%s关闭"(id));
}
}

class C {
S s;//类中构

this(int id) {
s = S(id);
}

// @disable ~this();//应禁止
}

void main() {
//只需1就可`显示`阿里环境下错误.
enum N = 1;
foreach (i; 0 .. N) {
auto c = new C(i);
}
}

​问题​​在遗漏的​​指导方针​​:​​类​​应该​​@disable​​析构器.​​取消注释​​该行时,上面程序正常工作.

当然,应该加上​​@disable ~this();​​作为行为准则.

你怎么看?

不.​​类析构器​​​用于清理​​非垃集​​​资源.只要坚持这点,就可​​安全​​运行它们.

​放入类​​的​​结构​​必须​​正确​​运行​​析构器​​,否则,会遇见​​可怕​​的不一致.

如,我不想在​​类​​中禁止​​RefCounted​​结构的析构.

如果关心在​​构 析构器​​中使用​​垃集​​,可用​​GC.inFinalizer​​检查.

我记得几年前,​​Andrei​​提议从​​语言​​中完全删除类​​析构器​​(或​​终结器​​,等等).有点​​极端​​,但反映了你的​​一般​​想法.

关于类​​析构器​​的一个观察是,如果不能​​清理资源​​(运行中不能依赖它,且禁止使用可能已​​收集​​的类引用),则​​*它们有何实际用途*​​,就没用.

​类​​析构器的默认版无用,非默认时有用.

因此,如果用户使用​​--DRT-gcopt=cleanup:none​​运行程序,碰巧在​​GC​​分配类中有个​​RefCounted​​结构,则搞砸了?

​便宜​​方法是使用像​​sprintf​​这样的​​@nogc​​方法?

:唔.也许​​准则​​应该是"​​析构器​​必须是​​@nogc"​​.

我​​同意​​.

可观察到:

​a)​​,对所有类​​@disable ~this()​​,这样可​​免受​​其他编写良好​​结构成员析构器​​影响.一般,​​此选项​​需要​​该类​​的应在释放​​垃集​​内存前调用的​​清理​​函数.

​b)​​,在每个有​​可能​​在​​类​​中使用的​​构析构器​​中考虑​​GC.inFinalizer()​​(不一定都适用).

​c)​​,​​构​​中也不要在​​析构器​​中分配​​垃集​​内存.

struct S {
int id;
string closingMessage; // <-- 很贵

this(int id) {
this.id = id;
this.closingMessage = format!"%s关闭"(id);
}

~this() {
// 这里不分配,很好.
closeConnection(closingMessage);
}
}

用​​@nogc​​​,如​​sprintf​​很便宜.