如何在析构函数中检查内存是否已经释放?
我有一个简单的坦克大战风格的游戏,使用 allegro 开源库。在我的 Tank 类中,我将位图对象的指针数组初始化为 0。然后,我使用 allegro 函数 create_bitmap 创建新对象,该函数分配内存并对其进行初始化。
然后我就照常做我的事。
问题是,当我像一个优秀的 OO 男孩一样去释放类析构函数中的位图内存时,我会使程序崩溃,因为在这个特定的程序中,allegro 库在类之前进行清理(释放它创建的位图对象)超出范围并被销毁。但它不会再次将我的指针设置为 NULL,因此我无法检查位图是否仍然有效,如果我尝试释放它们,它们将使程序崩溃。
有什么办法解决这个问题吗?如果指针不为 NULL,我可以检查它们是否有效吗?如果在程序中以不同的方式使用该类,我如何确定内存已被释放。就目前而言,我本质上是在不删除的情况下调用 new ,我不喜欢它。
I have a simple tank wars style game using the allegro open source library. In my tank class, I initialize arrays of pointers to bitmap objects to 0. Then I create new objects with an allegro function create_bitmap which allocates the memory and initializes it.
Then I go about my business as usual.
The problem is, when I go to release the bitmap memory in the class destructor like a good OO boy, I crash the program because in this specific program, the allegro library does its cleanup (which releases the bitmap objects it created) before the class goes out of scope and is destroyed. It doesn't set my pointers to NULL again though so I can't check if the bitmaps are still valid and if I try to release them they will crash the program.
Is there any way around this? Can I check for valid pointers if they are not NULL? How can I be SURE that the memory is freed if the class is used a different way within the program. As it stands right now, I'm essentially calling new without delete and I don't like it.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(9)
我认为问题不在于 allegro 本身释放位图(否则您不需要在退出时释放它们),而是在调用析构函数之前 allegro 库已被取消初始化。
为了确保首先调用析构函数,您可以做的是使用人工作用域:
I think the problem is not that allegro releases the bitmaps itself (or otherwise you wouldn't need to release them at exit) but that allegro library has been deinitialized before the destructor is called.
What you can do to ensure that the destructor is invoked first is to use an artificial scope:
您不应该使用原始指针数组。 Allegro 附带一个
create_bitmap
和一个destroy_bitmap
函数。这很好地映射了 C++ 的构造函数和析构函数的概念。您应该有一个AllegroPlusPlus::bitmap
类,它只管理一个位图。你的 Tank 类可以简单地拥有这些的数组。这是责任的分离。 Tank 类不应该对位图及其内存管理了解太多,并且位图类应该精确地处理一张位图。
您想在 Tank 类中回收位图。这没问题;通过良好地实现 bitmap::operator=(bitmap const&) 或其他重载,可以轻松完成此操作。但同样,让该分配成为位图类的责任,而不是坦克类的责任。
You shouldn't be using arrays of raw pointers. Allegro comes with a
create_bitmap
and adestroy_bitmap
function. That maps very nicely to the C++ concept of constructors and desctrutors. You should have anAllegroPlusPlus::bitmap
class, which manages exactly one bitmap. Your Tank class can tehn simply have an array of those.This is a seperation of responsibilities. The tank class should not know too much about bitmaps and their memoy management, and the bitmap class should handle precisely one bitmap.
You want to recycle bitmaps in your Tank class. This is no problem; it can be done easily with a good implementation of
bitmap::operator=(bitmap const&)
or other overloads. But again, make that assignment a responsibility of the bitmap class, not the tank class.不。但就你的情况而言,你不需要。由于 Allegro 承诺照顾其资源,因此您不必(也不得)干预 Allegro 资源的资源处理。特别是,由于您甚至不知道如何分配资源,因此您无法取消分配它们。
No. But in your case you don’t need to. Since Allegro promises to take care of its resources you don’t have to (and must not) meddle in the resource handling of Allegro resources. In particular, since you don’t even know how the resources are allocated, you cannot deallocate them.
显式管理内存的关键在于,虽然可以有多个指向同一内存区域的指针,但在任何时候,只有其中一个是指定的所有者,而所有其他指针仅共享它。当堆对象拥有其他堆对象时,它们构成一棵树,植根于某处的全局或局部作用域变量。
一旦您从初始 Allegro 调用返回,您应该将 Allegro 视为您传递给它的内存区域的所有者,并且将您自己的指针视为共享指针。
不,除非有一些分配器欺骗,否则您没有标准方法来确定内存是否有效。分配器技巧对于调试目的很有用,但不要弄乱库的内部结构。
The key to manage memory explicitly is that while you can have several pointers to the same memory area, at any one time, only one of them is the designated owner, while all other only share it. When heap objects own other heap objects, they constitute a tree, rooted in a globally or locally scoped variable somewhere.
You should consider Allegro to be the owner of memory areas you pass into it, and your own pointer just to be a shared pointer, once you return from the initial Allegro call.
And no, barring some allocator trickery, you have no standard way of determining whether memory is valid or not. Allocator trickery can be useful for debugging purposes, but don't mess with the internals of a library.
听起来像是一个相当可怕的泄漏抽象
你不能希望找到一种安全的销毁内存的方法如果您不确切知道它是如何分配的。清理功能听起来好像它的存在是有原因的并且正在做一项工作 - 只是必须忍受它。
您当然可以包装这些部分并在注释中包含一些文档,以便其他开发人员不会陷入同样的陷阱。
还要分析您的应用程序以确保没有泄漏。
Sounds like a rather horrible leaky abstraction
You cannot hope to find a safe method of destroying memory if you do not know exactly how it has been allocated. The cleanup function sounds like it's there for a reason and doing a job - just gotta live with it.
You could of course wrap these bits and include some documentation in comments so that other developers don't fall into the same trap.
Also profile your application to make sure there's no leaking.
析构函数什么时候被调用?是在 Allegro 图书馆关闭之后吗?如果是这样那么您可以先删除所有对象吗?
When is the destructor being called? Is it after the Allegro library has been shut down? If so then can you delete all the objects first?
你确定你正确使用这个吗?我挖出了一些旧的 Allegro 代码,并且有一个带有 create_bitmap 调用的构造函数和一个带有release_bitmap 调用的析构函数,它工作得很好。
我不记得有关 Allegro 自动为您释放内存的任何事情。您是否意外地用一些非内存值覆盖了指针?还有其他地方可以释放该指针吗?
Are you sure you are using this correctly? I have dug out some of my old Allegro code and I have a constructor with a create_bitmap call and a destructor with a release_bitmap call and it worked fine.
I don't remember anything about Allegro releasing memory for you automatically. Are you accidently overwriting the pointer with some non-memory value? Is there another place where this pointer is being freed?
处理指向堆内存的多个指针时使用引用计数。基本上,如果您对同一内存有多个引用并删除其中一个,则另一个引用可能仍然认为它存在。
http://en.wikipedia.org/wiki/Reference_counting
Use reference counting when dealing with multiple pointers to heap memory. Basically, if you have multiple references to the same memory and delete one, the other reference might still think it exists.
http://en.wikipedia.org/wiki/Reference_counting
我想说你应该确保你的对象在关闭 Allegro 之前全部被销毁,你可以通过在关闭 Allegro 之前关闭它们存在的范围(如果它们在堆栈上)来轻松地做到这一点。
如果您需要在此之前关闭 Allegro(例如,由于致命错误),那么您可以只调用 exit,在这种情况下,不会运行析构函数(但您的程序仍然不会崩溃)。
不要花太多时间确保程序在退出时清理,节省精力确保它在运行时不会泄漏:)
I'd say you should ensure that your objects are all destructed before shutting Allegro down, you can do this easily enough by (if they're on-stack) closing the scope they exist in before shutting down Allegro.
If you need to shut down Allegro earlier than this (e.g. because of a fatal error) then you could just call exit in which case no destructors get run (but your program still won't crash).
Don't spend too much time making sure that the program cleans up on exit, save your effort on making sure it doesn't leak while it's running :)