如何在析构函数中检查内存是否已经释放?

发布于 2024-08-09 15:01:11 字数 410 浏览 13 评论 0原文

我有一个简单的坦克大战风格的游戏,使用 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 技术交流群。

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

发布评论

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

评论(9

过度放纵 2024-08-16 15:01:11

我认为问题不在于 allegro 本身释放位图(否则您不需要在退出时释放它们),而是在调用析构函数之前 allegro 库已被取消初始化。

int main()
{
    ObjectManagingBitmaps o;
    ...
    return 0;
    //allegro automatically shut down here
} //o destructor invoked here
END_OF_MAIN()

为了确保首先调用析构函数,您可以做的是使用人工作用域:

int main()
{
    {
    ObjectManagingBitmaps o;
    ...
    } //o destructor invoked here
    return 0;
    //allegro automatically shut down here
} 
END_OF_MAIN()

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.

int main()
{
    ObjectManagingBitmaps o;
    ...
    return 0;
    //allegro automatically shut down here
} //o destructor invoked here
END_OF_MAIN()

What you can do to ensure that the destructor is invoked first is to use an artificial scope:

int main()
{
    {
    ObjectManagingBitmaps o;
    ...
    } //o destructor invoked here
    return 0;
    //allegro automatically shut down here
} 
END_OF_MAIN()
抽个烟儿 2024-08-16 15:01:11

您不应该使用原始指针数组。 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 a destroy_bitmap function. That maps very nicely to the C++ concept of constructors and desctrutors. You should have an AllegroPlusPlus::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.

我爱人 2024-08-16 15:01:11

如果指针不为 NULL,我可以检查它们是否有效吗?

不。但就你的情况而言,你不需要。由于 Allegro 承诺照顾其资源,因此您不必(也不得)干预 Allegro 资源的资源处理。特别是,由于您甚至不知道如何分配资源,因此您无法取消分配它们。

Can I check for valid pointers if they are not NULL?

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.

烈酒灼喉 2024-08-16 15:01:11

显式管理内存的关键在于,虽然可以有多个指向同一内存区域的指针,但在任何时候,只有其中一个是指定的所有者,而所有其他指针仅共享它。当堆对象拥有其他堆对象时,它们构成一棵树,植根于某处的全局或局部作用域变量。

一旦您从初始 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.

陪你搞怪i 2024-08-16 15:01:11

听起来像是一个相当可怕的泄漏抽象

你不能希望找到一种安全的销毁内存的方法如果您不确切知道它是如何分配的。清理功能听起来好像它的存在是有原因的并且正在做一项工作 - 只是必须忍受它。

您当然可以包装这些部分并在注释中包含一些文档,以便其他开发人员不会陷入同样的​​陷阱。

还要分析您的应用程序以确保没有泄漏。

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.

寂寞清仓 2024-08-16 15:01:11

析构函数什么时候被调用?是在 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?

玩世 2024-08-16 15:01:11

你确定你正确使用这个吗?我挖出了一些旧的 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?

靑春怀旧 2024-08-16 15:01:11

处理指向堆内存的多个指针时使用引用计数。基本上,如果您对同一内存有多个引用并删除其中一个,则另一个引用可能仍然认为它存在。

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

数理化全能战士 2024-08-16 15:01:11

我想说你应该确保你的对象在关闭 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 :)

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