Как проверить, освободилась ли память в Destructor? - PullRequest
2 голосов
/ 02 ноября 2009

У меня есть простая игра в стиле танковых войн с использованием библиотеки с открытым исходным кодом allegro. В моем классе tank я инициализирую массивы указателей для растровых объектов равными 0. Затем я создаю новые объекты с помощью функции allegro create_bitmap, которая выделяет память и инициализирует ее.

Тогда я занимаюсь своими делами как обычно.

Проблема в том, что когда я собираюсь освободить растровую память в деструкторе класса, как хороший ОО-мальчик, я сбой программы, потому что в этой конкретной программе библиотека allegro выполняет очистку (которая освобождает созданные им растровые объекты) до того, как класс выйдет за рамки и будет уничтожен. Он не устанавливает мои указатели снова в NULL, поэтому я не могу проверить, все ли действительны ли растровые изображения, и если я попытаюсь их освободить, программа вылетит.

Есть ли способ обойти это? Могу ли я проверить действительные указатели, если они не равны NULL? Как я могу быть уверен, что память освобождается, если в программе используется другой способ. В настоящее время я, по сути, звоню new без удаления, и мне это не нравится.

Ответы [ 9 ]

5 голосов
/ 03 ноября 2009

Я думаю, что проблема не в том, что 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()
4 голосов
/ 02 ноября 2009

Вы не должны использовать массивы сырых указателей. Allegro поставляется с функциями create_bitmap и destroy_bitmap. Это очень хорошо согласуется с концепцией C ++ конструкторов и описателей. У вас должен быть класс AllegroPlusPlus::bitmap, который управляет ровно одним растровым изображением. Ваш класс Tank может просто иметь множество из них.

Это разделение обязанностей. Класс tank не должен знать слишком много о растровых изображениях и управлении ими, а класс растровых изображений должен обрабатывать только одно растровое изображение.

Вы хотите перерабатывать растровые изображения в своем классе Tank. Это не проблема; это можно легко сделать с хорошей реализацией bitmap::operator=(bitmap const&) или другими перегрузками. Но опять же, возложите на это назначение ответственность за класс точечного рисунка, а не за класс резервуара.

2 голосов
/ 02 ноября 2009

Могу ли я проверить правильность указателей, если они не равны NULL?

Нет. Но в вашем случае вам это не нужно. Поскольку Allegro обещает заботиться о своих ресурсах, вам не нужно (и не нужно) вмешиваться в обработку ресурсов Allegro. В частности, поскольку вы даже не знаете , как распределяются ресурсы, вы не можете освободить их.

1 голос
/ 02 ноября 2009

Когда вызывается деструктор? Это после закрытия библиотеки Allegro? Если да, то можете ли вы сначала удалить все объекты?

1 голос
/ 02 ноября 2009

Звучит как довольно ужасная дырявая абстракция

Вы не можете надеяться найти безопасный способ уничтожения памяти, если не знаете точно, как она была распределена. Функция очистки звучит так, как будто она существует по какой-то причине и выполняет свою работу - просто надо с этим жить.

Конечно, вы можете обернуть эти биты и включить некоторую документацию в комментарии, чтобы другие разработчики не попали в ту же ловушку.

Также профилируйте свою заявку, чтобы убедиться в отсутствии утечек.

1 голос
/ 02 ноября 2009

Ключ для явного управления памятью заключается в том, что, хотя вы можете иметь несколько указателей на одну и ту же область памяти, в любое время только один из них является назначенным владельцем, в то время как все остальные только делят его. Когда объекты кучи владеют другими объектами кучи, они образуют дерево, укорененное где-то в глобальной или локальной переменной.

Вы должны считать, что Allegro является владельцем областей памяти, которые вы передаете в него, а ваш собственный указатель - просто указателем общего доступа, как только вы вернетесь из первоначального вызова Allegro.

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

0 голосов
/ 14 ноября 2009

Я бы сказал, что вы должны убедиться, что все ваши объекты уничтожены, прежде чем выключать Allegro, вы можете сделать это достаточно легко, (если они в стеке), закрыв область, в которой они существуют, перед выключением Allegro.

Если вам нужно закрыть Allegro раньше, чем это (например, из-за фатальной ошибки), тогда вы можете просто вызвать exit, и в этом случае деструкторы не запустятся (но ваша программа по-прежнему не будет аварийно завершаться).

Не тратьте слишком много времени, чтобы убедиться, что программа очищается при выходе, сэкономьте свои усилия, чтобы убедиться, что она не протекает во время работы:)

0 голосов
/ 03 ноября 2009

Используйте подсчет ссылок при работе с несколькими указателями для кучи памяти. По сути, если у вас есть несколько ссылок на одну и ту же память и одна из них удалена, другая ссылка все еще может думать, что она существует.

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

0 голосов
/ 02 ноября 2009

Вы уверены, что используете это правильно? Я выкопал некоторые из моего старого кода Allegro, и у меня есть конструктор с вызовом create_bitmap и деструктор с вызовом release_bitmap, и он работал нормально.

Я ничего не помню, чтобы Аллегро высвободил память для вас автоматически. Вы случайно перезаписываете указатель не значением памяти? Есть ли другое место, где этот указатель освобождается?

...