【问题标题】:0xC0000005: Access violation reading location error in destructor0xC0000005:析构函数中的访问冲突读取位置错误
【发布时间】:2019-09-04 10:04:51
【问题描述】:

我有一个类用于将图像文件加载到位图并保留对这些位图的引用。我想在稍后的某个时间(例如在关闭应用程序之前)释放这些资源。

所以我的班级(是单身人士)设计如下:

class ImageManager
{
public:
   static ImageManager &getInstance();
   ImageManager(ImageManager const&) = delete;
   void operator=(ImageManager const&) = delete;
   void loagImage(char *location);
   ~ImageManager();
private:
   ImageManager();
   ALLEGRO_BITMAP *image = nullptr;
}

在构造函数中真的没什么。只需加载与处理位图相关的附加组件。没有创建原始指针。

loadImage() 实现如下:

void ImageManager::loadImage(char *location)
{
    if(!location)
    {
       throw std::invalid_argument("Location cannot be null.");
    }
    image = al_load_bitmap(location);
}

析构函数的定义如下

ImageManager::~ImageManager()
{
   if(image)
   {
       al_destroy_bitmap(image); // Here I get the access violation exception.
   }
}

这个类在main.cpp中的使用方式是这样的:

int main(int argc, char *args[])
{
    ImageManager &imgManager = ImageManager::getInstance();
    imgManager.loadImage("valid/location");

    return 0;
}

如果我在加载位图的同一个函数中调用al_destroy_bitmap(),则不会出错。只有当我尝试在析构函数中调用它时才会发生这种情况。

我在使用 VS17 的 Windows 10 上。我看到了许多关于同一主题的问题,但我无法使用那里的答案找出错误。如果您需要,我还将在此处链接到这两种 allegro 方法:

  1. al_load_bitmap()
  2. al_destroy_bitmap()

编辑:

我的getInstance()方法是:

ImageManager &ImageManager::getInstance()
{
    static ImageManager instance;
    return instance;
}

编辑 2:

确切的错误是0xC0000005: Access violation reading location 0xDDDDDDF1.

【问题讨论】:

  • 你的 getInstance 是什么样的?
  • 如果在return 0 之前明确销毁imgManager 实例会发生什么?在调用ImageManager::~ImageManager 之前,位图可能已经被销毁。
  • @Anders 添加了getInstance() 方法。
  • @J.R.尝试显式调用析构函数,同样的错误......我认为你是对的,位图已经被释放,只是不知道在哪里......
  • 如何调用析构函数?另一项测试是将image 设置为nullptr in ImageManager::~ImageManager...

标签: pointers c++14 allegro5


【解决方案1】:

Allegro 5 不能很好地处理像单例这样的全局变量。

要记住的事情:

1) 全局对象或对静态初始化的全局调用发生在调用al_init 之前。这意味着在其构造函数中调用 allegro 函数将失败。

2) 全局静态变量比 main 和 atexit 更有效。这意味着它们的析构函数将在 allegro 通常关闭后运行。 al_install_system 钩住 atexit 以关闭它的库,除非你明确告诉它不要这样做。这意味着如果幸运的话,对像 al_destroy_bitmap 这样的 allegro 函数的调用将失败并出现段错误。

您必须在 atexit 和 main 退出或调用 al_uninstall_system 之前明确“关闭”您的 ImageManager 实例。

【讨论】:

    【解决方案2】:

    instance 更改为一个指针,让getInstance 创建一个实例,并在return 0 之前添加一个显式的destroyInstance 调用以删除该实例可能会解决问题,因为您不再有一个销毁/释放序列退出 main 后不受您的控制。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多