0xC0000005: ошибка определения местоположения при нарушении доступа в деструкторе

#pointers #c 14 #allegro5

#указатели #c 14 #allegro5

Вопрос:

У меня есть класс, который предназначен для загрузки файлов изображений в растровые изображения и сохранения ссылок на эти растровые изображения. Я хочу освободить эти ресурсы в какой-то момент позже, например, непосредственно перед закрытием приложения.

Итак, мой класс (одноэлементный) разработан следующим образом:

 class ImageManager
{
public:
   static ImageManager amp;getInstance();
   ImageManager(ImageManager constamp;) = delete;
   void operator=(ImageManager constamp;) = 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 amp;imgManager = ImageManager::getInstance();
    imgManager.loadImage("valid/location");

    return 0;
}
 

Если я вызываю al_destroy_bitmap() ту же функцию, которая загружает растровое изображение, ошибки нет. Это происходит только тогда, когда я пытаюсь вызвать его в деструкторе.

Я в Windows 10 использую VS17. Я видел несколько вопросов по той же теме, но я не смог выяснить ошибку, используя ответы там. Я также дам ссылку на два метода allegro здесь, если вам нужно:

  1. al_load_bitmap()
  2. al_destroy_bitmap()

Редактировать:

Мой getInstance() метод:

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

ПРАВКА 2:

Точная ошибка 0xC0000005: Access violation reading location 0xDDDDDDF1.

Комментарии:

1. как выглядит ваш getInstance?

2. Что произойдет, если вы явно уничтожите imgManager экземпляр раньше return 0 ? Возможно, растровое изображение уже было уничтожено до ImageManager::~ImageManager вызова.

3. @Anders добавил getInstance() метод.

4. @J.R. Попытался явно вызвать деструктор, та же ошибка… Я думаю, вы правы в том, что растровое изображение уже освобождено, просто не могу понять, где…

5. Как вы вызываете деструктор? Другим тестом было бы установить image значение nullptr in ImageManager::~ImageManager

Ответ №1:

Allegro 5 не очень хорошо работает с глобальными значениями, такими как синглтоны.

Что нужно помнить :

1) Глобальные объекты или глобальные вызовы статической инициализации происходят до al_init вызова. Это означает, что вызовы функций allegro внутри их конструкторов завершатся неудачей.

2) Глобальная статика переживает main и atexit. Это означает, что их деструкторы будут запускаться после завершения работы allegro. al_install_system перехватывает atexit для отключения своей библиотеки, если вы специально не скажете этого не делать. Это означает, что вызовы функций allegro, таких как al_destroy_bitmap will fail и segfault, если вам повезет.

Вам придется явно «выключить» ваш экземпляр ImageManager перед выходом atexit и main ИЛИ перед вызовом al_uninstall_system.

Ответ №2:

Изменение instance на указатель, getInstance создание экземпляра и добавление явного destroyInstance вызова для удаления экземпляра до return 0 этого может решить проблему, поскольку у вас больше нет последовательности уничтожения / освобождения, которая находится вне вашего контроля после выхода из main.