2

我有一个使用 allegro 开源库的简单坦克战争风格游戏。在我的坦克类中,我将指向位图对象的指针数组初始化为 0。然后我使用 allegro 函数 create_bitmap 创建新对象,该函数分配内存并对其进行初始化。

然后我照常做我的事情。

问题是,当我像一个好的 OO 男孩一样去释放类析构函数中的位图内存时,我使程序崩溃,因为在这个特定的程序中,快板库在类之前进行了清理(释放了它创建的位图对象)超出范围并被销毁。它不会再次将我的指针设置为 NULL,所以我无法检查位图是否仍然有效,如果我尝试释放它们,它们会使程序崩溃。

有没有办法解决?如果它们不为 NULL,我可以检查有效的指针吗?如果在程序中以不同的方式使用该类,我如何确定内存已被释放。就目前而言,我本质上是在没有删除的情况下调用 new 并且我不喜欢它。

4

9 回答 9

5

我认为问题不在于 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()
于 2009-11-02T23:10:36.053 回答
3

您不应该使用原始指针数组。Allegro 带有一个create_bitmap和一个destroy_bitmap函数。这与 C++ 构造函数和析构函数的概念非常吻合。你应该有一个AllegroPlusPlus::bitmap类,它只管理一个位图。您的 Tank 类可以简单地拥有一组这些。

这是职责分离。tank 类不应该对位图及其内存管理了解太多,而 bitmap 类应该只处理一个位图。

您想在 Tank 类中回收位图。这没问题;它可以通过良好的实现bitmap::operator=(bitmap const&)或其他重载轻松完成。但同样,让该分配成为位图类的职责,而不是坦克类。

于 2009-11-02T15:53:42.650 回答
2

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

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

于 2009-11-02T15:04:23.717 回答
1

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

一旦您从初始 Allegro 调用返回,您应该将 Allegro 视为您传递给它的内存区域的所有者,并且您自己的指针只是一个共享指针。

不,除非有一些分配器的诡计,否则你没有标准的方法来确定内存是否有效。分配器技巧可用于调试目的,但不要弄乱库的内部结构。

于 2009-11-02T15:08:14.257 回答
1

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

如果您不确切知道它是如何分配的,那么您就不能指望找到一种安全的方法来破坏内存。清理功能听起来是有原因的,并且在做一项工作 - 只是要忍受它。

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

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

于 2009-11-02T15:09:23.193 回答
1

什么时候调用析构函数?是在 Allegro 库关闭之后吗?如果是这样,您可以先删除所有对象吗?

于 2009-11-02T19:53:15.197 回答
0

你确定你使用正确吗?我挖出了一些我的旧 Allegro 代码,我有一个带有 create_bitmap 调用的构造函数和一个带有 release_bitmap 调用的析构函数,它工作正常。

我不记得 Allegro 自动为你释放内存的任何事情。您是否不小心用一些非内存值覆盖了指针?是否还有其他地方可以释放此指针?

于 2009-11-02T15:31:51.937 回答
0

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

http://en.wikipedia.org/wiki/Reference_counting

于 2009-11-02T22:21:54.533 回答
0

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 :)

于 2009-11-13T22:54:49.533 回答