8

例如,在 c++ 中使用 Direct3D 时,我可以编写一个“Cube”类,其中包含一个“ID3D11Buffer* vertexBuffer_”,并确保该 Cube 对象的析构函数调用 vertexBuffer_->Release()。

我可以有一个包含“unique_ptr cube_”对象的“场景”类。所以我知道当我删除我的场景时,立方体将被删除,因此将调用它正在使用的 D3D 资源的释放。

在 DI 中无法做到这一点。我可以编写析构函数,但我不知道什么时候会调用它们。如果 GC 不需要内存,它们可能永远不会被调用......

那么在 D 中处理这种事情的最佳方法是什么?我可以为每个对象添加一个“Free”成员函数,以释放它自己的所有资源并在它拥有的任何对象上调用“Free”,但这似乎是一个容易出错的手动操作,并且从 C++ 倒退了一步。

有没有更好的方法来处理 D 中的这种事情?

4

2 回答 2

6

您可以在堆栈上使用结构。具有确定性破坏。您甚至可以使用std.typecons.RefCounted对其进行重新计数。如果要保证析构函数运行,请不要在堆上使用结构。目前,我认为如果将结构体的析构函数放在堆上,它们就不会运行,因为 GC 没有它需要这样做的信息(这应该在未来虽然)。

但是如果你坚持把它放在一个类的堆上,并且你想显式地销毁这个对象,那么你可以调用clear它:

clear(obj);

这将调用对象的析构函数,然后将其置于无效状态,之后任何尝试使用它的东西都会崩溃(IIRC,虚拟表被清零)。但实际上并没有释放内存。那是GC的工作。并且不要使用delete. 它将被弃用。我实际上很惊讶它还没有,因为它已经计划了很长时间来摆脱它。

当然,一种选择是使用显式函数来调用以释放资源。这是否是一个好主意取决于你在做什么。但无论如何,类是由 GC 收集的,而不是在您选择时释放。

正在对自定义分配器进行工作,这将为您提供更多关于如何分配类的选项,其中一个可能允许您对类进行更具确定性的破坏,但这还没有准备好。

如果你感觉很疯狂,你可以使用std.typecons.scoped,它取代了即将被弃用的类型修饰符scope(尽管scope在其他情况下仍然存在 - 例如scope语句)。它将一个类放在堆栈上。但这是不安全的(这就是为什么scope在这种情况下会消失),如果要将对象粘贴在堆栈上,您可能还不如只使用结构。

编辑:您也可以使用mallocandfreestd.conv.emplace将对象放入非 GC 分配的内存块中,就像在 C++ 中一样,但我认为您必须显式调用析构函数才能获取它运行,因为free不了解析构函数(它是一个 C 函数)。这将具有使内存与资源一起消失的优势(而clear在 GC 堆上的对象上使用只会破坏对象的内容,而不是释放内存),但我不知道这会让你买多少clear在 GC 分配的对象上使用。

但是,您可以创建一个类似于为您new执行mallocand的自由函数,然后创建一个类似于调用析构函数的自由函数 and ,这将给您与 C++ 相同的情况。事实上,我想知道这是否足以使它成为标准库。不过,这可能最终会出现在自定义分配器中。所以,如果在不久的将来,你可以使用自定义分配器来做类似的事情,我一点也不感到惊讶emplacedeletefree

auto obj = customAllocObj.create!MyObj(args);
//Do stuff...
customAllocObj.destroy(obj);

而且我认为这将很好地解决您的问题,因为这与您在 C++ 中所拥有的基本相同,只是使用库函数而不是使用内置的newdelete. 我想我会在新闻组上提出来。我希望至少有一些人会喜欢这样的功能,而且这似乎与自定义分配器很相配。

于 2012-02-23T11:18:16.300 回答
2

澄清一下:总是调用析构函数。如果一个对象在应用程序关闭时还没有被终结,GC 就会运行它的终结器。

我看不出手动调用 free() 函数来删除顶点缓冲区比必须在 C++ 中手动管理内存更容易出错。无论如何,你可能想看看:http ://www.dlang.org/phobos/std_typecons.html#scoped和http://www.dlang.org/phobos/std_typecons.html#RefCounted

于 2012-02-23T10:09:48.293 回答