D语言释放资源

发布于 2025-01-08 19:00:10 字数 438 浏览 1 评论 0原文

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

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

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

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

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

When using Direct3D in c++ I can write a "Cube" class for example, that contains a "ID3D11Buffer* vertexBuffer_" and ensure that the destructor for that Cube object calls vertexBuffer_->Release().

I can have a "Scene" class containing a "unique_ptr cube_" object. So that I know that when I delete my scene, the cube will be deleted, and that will consequently call release on the D3D resources it is using.

In D I can't do this. I can write destructors but I have no idea when they will be called. If the GC doesn't require the memory they may never be called...

So what is the best way to handle this kind of thing in D? I could add a "Free" member function to each of the objects that frees all of it's own resources and calls "Free" on any objects it owns, but this seems an error prone manual operation and a step backwards from C++.

Is there a better way to handle this kind of thing in D?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

猫卆 2025-01-15 19:00:10

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

但是,如果您坚持将其放入类中的堆中,并且想要显式销毁该对象,那么您可以对其调用 clear

clear(obj);

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

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

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

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

编辑:您还可以将mallocfreestd.conv.emplace 将对象放入非 GC 分配的内存块中,就像在 C++ 中一样,但我认为你' d 必须显式调用析构函数让它运行,因为 free 不理解析构函数(它是一个 C 函数)。这样做的好处是使内存与资源一起消失(而在 GC 堆上的对象上使用 clear 只会破坏对象的内容,而不是释放内存),但我不这样做我不知道这比在 GC 分配的对象上使用 clear 更重要。

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

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

,而且我认为这会很好地解决您的问题,因为这本质上与您要做的事情相同在 C++ 中,仅使用库函数而不是使用内置的 newdelete。我想我会在新闻组中提出它。我预计至少有一些人会喜欢这样的功能,而且这似乎非常适合自定义分配器。

You could use a struct on the stack. That has deterministic destruction. You can even have it be refcounted by using std.typecons.RefCounted. Don't use a struct on the heap though if you want to guarantee that the destructor runs. At the moment, I don't think that structs' destructors ever get run if they're put on the heap, because the GC doesn't have the information that it needs to do so (that should be fixed at some point in the future though).

But if you insist on putting it in on the heap in a class, and you want to explicitly destroy the object, then you can call clear on it:

clear(obj);

That will call the object's destructor and then put it in an invalid state, and anything that tries to use it after that should blow up (IIRC, the virtual table gets zeroed out). But the memory isn't actually freed. That's the GC's job. And don't use delete. It's going to be deprecated. I'm actually surprised that it hasn't been yet, since it's been planned for ages to get rid of it.

And of course, one option is to have an explicit function that you call to release the resources. Whether that's a good idea or not depends on what you're doing. But regardless, classes are intended to be collected by the GC and not be freed whenever you choose to.

Work is being done on custom allocators, which would give you more options for how to allocate a class, and one of those would probably allow you to have more deterministic destruction of classes, but that's not ready yet.

And if you're feeling crazy, you can use std.typecons.scoped, which replaces the soon to be deprecated type modifier scope (though scope is sticking around in other contexts - such as scope statements). It puts a class on the stack. But that's unsafe (which is why scope is going away in this context), and you probably might as well just use a struct if you're going to stick the object on the stack.

EDIT: You could also use malloc and free with std.conv.emplace to put the object in a non-GC allocated chunk of memory like you'd have in C++, but I think that you'd have to explicitly call the destructor to get it run, since free doesn't understand about destructors (it being a C function). That would have the advantage of making the memory go away along with the resource (whereas using clear on an object on the GC heap would just destroy the object's contents, not free the memory), but I don't know that that buys you much over using clear on a GC-allocated object.

However, you could then create a free function similar to new which does the malloc and emplace for you, and then have a free function similar to delete which calls the destructor and free, which would give you the same situation as C++. In fact, I wonder if that would be useful enough to make it into the standard library. That's probably the sort of thing that'll end up in the custom allocators though. So, it wouldn't surprise me at all if in the relatively near future, you could use a custom allocator to do something like

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

And I would think that that would solve your problem fairly well given that that's essentially the same thing that you'd have in C++, just with library functions rather than with the built-in new and delete. I think that I'll bring it up on the newsgroup. I expect that there are at least some folks who would like such a feature, and that does seem to fit in nicely with custom allocators.

妄断弥空 2025-01-15 19:00:10

只是为了澄清:析构函数总是被调用。如果应用程序关闭时对象尚未最终确定,则 GC 会运行其终结器。

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

Just to clarify: Destructors are always called. If an object has not been finalized by the time the application shuts down, the GC runs its finalizer.

I don't see how manually calling a free() function to delete the vertex buffer is any more error prone than having to manage memory manually in C++. Anyway, you may want to look at: http://www.dlang.org/phobos/std_typecons.html#scoped and http://www.dlang.org/phobos/std_typecons.html#RefCounted

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文