#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 здесь, если вам нужно:
Редактировать:
Мой 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
inImageManager::~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.