Destroying bitmaps
Kauhiz

Is there any reason that a bitmap should not be destroyed? The reason I ask is because I get a crash when I call destroy_bitmap for some bitmaps. The bitmaps in question are loaded from a datafile, and I'm positive that they aren't being used after the destroy_* function has been called. I also have the same problem with some fonts, also loaded from a datafile. Not all the bitmaps loaded from the datafile cause a crash when destroyed, though.

Also, just for reference, in my triple buffering code I do this:

1int on_page = 0;
2 
3BITMAP *active_page;
4BITMAP *page[3];
5 
6...
7 
8page[0] = create_video_bitmap(SCREEN_W, SCREEN_H);
9page[1] = create_video_bitmap(SCREEN_W, SCREEN_H);
10page[2] = create_video_bitmap(SCREEN_W, SCREEN_H);
11
12active_page = page[0];
13 
14...
15 
16on_page = (on_page + 1) % 3;
17active_page = page[on_page];
18 
19...
20 
21destroy_bitmap(page[0]);
22destroy_bitmap(page[1]);
23destroy_bitmap(page[2]);

Then all drawing is done to active page. I'm not supposed to call destroy_bitmap for active_page, right?

Matthew Leverton

Don't destroy a bitmap if:

  • It's loaded from a datafile (load_datafile, load_datafile_object, etc),

  • It still has active sub bitmaps, or

  • The mouse is displayed on it.

Sirocco
Quote:

Is there any reason that a bitmap should not be destroyed?

The most obvious one being... don't laugh... if you have previously destroyed it or never created it in the first place :) Destroying a non-existent bitmap will usually result in a crash. In your case you might want to make sure your create_video_bitmap calls aren't failing.

CursedTyrant
Quote:

Destroying a non-existent bitmap will usually result in a crash.

IIRC destroy_bitmap() doesn't crash on NULL...

Sirocco
Quote:

IIRC destroy_bitmap() doesn't crash on NULL...

It almost always does for me, but I'm not using the very latest version of Allegro.

Felipe Maia
Quote:

IIRC destroy_bitmap() doesn't crash on NULL...

Most people don't NULL their stuff.

[edit]

Quote:

I'm not supposed to call destroy_bitmap for active_page, right?

No, active_page only holds the address to the bitmap, and not the bitmap itself, so you should only destroy page[0], page[1], page[2] when you exit your program.

Evert
Quote:

It almost always does for me, but I'm not using the very latest version of Allegro.

As far as I know, it has been valid to pass NULL to destroy_bitmap() since forever. What version of Allegro are you using?

Quote:

Is there any reason that a bitmap should not be destroyed?

What you allocate, you should free as well.

Quote:

The reason I ask is because I get a crash when I call destroy_bitmap for some bitmaps. The bitmaps in question are loaded from a datafile,

The dat entries of a datafile are freed by unload_datafile(). You did not allocate the memory for those bitmaps, so you should not destroy tham.

Quote:

I also have the same problem with some fonts, also loaded from a datafile

Same problem.

If you allocate the object yourself (ie, get it from a function that returns a BITMAP* or a FONT*), then you have to free it. Otherwise you don't. Think of it this way: you don't free Allegro's default font or the screen bitmap either.

Paladin

Simply calling

unload_datafile(datfile);

should free up all the files you used in the datafile. I may be wrong but this is always what I do. Also be sure not to free up a pointer such as active_page. It only needs to be freed if you actually load a bitmap or a create a bitmap with it. You might also call

show_mouse(NULL);

before you free all the memory that way you can be sure the mouse isn't be displayed. I could be wrong since I'm still a beginner, but I had the same problems a couple of days ago. :P

Evert
Quote:

You might also call

show_mouse(NULL);

before you free all the memory that way you can be sure the mouse isn't be displayed.

Only nescessary if you explicitly call set_gfx_mode() to destroy the screen (assuming that you don't display the mouse on a different surface, which is generally a silly thing to do).

Kauhiz

Yeah, that makes sense, thanks guys.

[EDIT]
One more question: if I create sub-bitmaps of a bitmap I loaded from a datafile, do I have to destroy the sub-bitmaps?

Sirocco
Quote:

Most people don't NULL their stuff.

Quote:

As far as I know, it has been valid to pass NULL to destroy_bitmap() since forever. What version of Allegro are you using?

Sure, but this code seg faults every time for me:

pseudo code crap below:

BITMAP *foo;

void some_routine()
{
.
// We never created the bitmap
.
destroy_bitmap(foo);
}

Right now I think I'm using 4.03.

Felipe Maia

You're just declaring foo, so it has the value that was previously on the memory, which can be anything. Do this not to segfault:

BITMAP *foo = NULL;

void some_routine()
{
.
.
.
destroy_bitmap(foo);
}

Sirocco

Right, that's what I'm talking about. Guess I was misunderstood earlier in the thread.

Thomas Fjellstrom
Quote:

Guess I was misunderstood earlier in the thread.

Maybe everyone misunderstood ;) You're talking about uninitialized variables being "free"d, while everyone else is talking specifically about passing NULL (or variables set to NULL) to destroy_bitmap. These are two very different things.

Sirocco

It's early. I'm not awake yet. Sue me. Regardless, the advice is valid.

Richard Phipps

Aren't global uninitialised variables (including Bitmaps) set to NULL? I thought only local variables could hold any value.

axilmar

What about bitmap destruction on program exit? I have my bitmaps encapsulated in a Bitmap class (C++) which is destroyed probably after allegro exits. Does allegro destroy its bitmaps automatically on exit?

Richard Phipps

Quote:

Does allegro destroy its bitmaps automatically on exit?

No.

axilmar

Then why I can not destroy a bitmap after allegro exits? the program crashes within the destructor of the Bitmap class calling the 'destroy_bitmap' function.

I guess it may be something with allegro cleanup taking place before bitmap destruction. Is there a way to destroy the bitmaps before allegro exits?

Richard Phipps

Can't you call the cleanup function before your program ends? Or can you not add with atexit a cleanup function?

HoHo
Quote:

Aren't global uninitialised variables (including Bitmaps) set to NULL?

it is not quaranteed. I think GCC does that only in debug mode

Quote:

I thought only local variables could hold any value.

huh?

As for cleaning up on program exit, I would simply do something like this:

1Object *bunc, *of, *globals;
2 
3void init(){
4 intAllegro();
5 initGlobalObjects();
6}
7void run(){
8 while (gameGoesOn){
9 doStuff();
10 }
11}
12void exit(){
13 freeGlobalObjects();
14}
15 
16int main(){
17 init();
18 run();
19 exit();
20}
21END_OF_MAIN()

I would stay away from non-pointer global objects that have destructors that free allegro objects. The order of destroying objects is not defined and when allegro itself closes before your allegro objects are freed you are screwed. With global pointers you should have no such problems.

Kauhiz
me said:

One more question: if I create sub-bitmaps of a bitmap I loaded from a datafile, do I have to destroy the sub-bitmaps?

Well?

HoHo

Thinking logically, yes you have to destroy them yourself because you created them.

Sirocco
Quote:

One more question: if I create sub-bitmaps of a bitmap I loaded from a datafile, do I have to destroy the sub-bitmaps?

The general rule is that anything you create, you must destroy.

FMC

Yes

[edit]late :P
but i add this:

the manual said:

Return value: Returns a pointer to the created sub bitmap, or NULL if the sub bitmap could not be created. Remember to free the sub bitmap before freeing the parent bitmap to avoid memory leaks and potential crashes accessing memory which has been freed.

axilmar
Quote:

I would stay away from non-pointer global objects that have destructors that free allegro objects. The order of destroying objects is not defined and when allegro itself closes before your allegro objects are freed you are screwed. With global pointers you should have no such problems.

I solved the problem by installing an exit handler which is implicitely installed at first chance (after allegro is initialized).

I think allegro should have a user-defined shutdown callback which is invoked at 'allegro_exit' in order to release any allegro resources at the right time...the exit point of an app can be other than main.

Evert
Quote:

Then why I can not destroy a bitmap after allegro exits?

Because you cannot call Allegro functions when Allegro is not initialised (either before install_allegro() or after allegro_exit()).

Felipe Maia
Quote:

I think allegro should have a user-defined shutdown callback which is invoked at 'allegro_exit' in order to release any allegro resources at the right time...the exit point of an app can be other than main.

Why? If you can just put a function before your program closes, that doesn't make sense at all. Besides, those aren't allegro resources, they're yours resources, you created them, not allegro.

Paladin

Why would you want to explictly call set_gfx_mode(); to destroy the screen? Does it destroy every bitmap as well?

axilmar
Quote:

Why? If you can just put a function before your program closes, that doesn't make sense at all.

1. exit() might be called at various places.
2. It makes my library's interface simpler.

Quote:

Besides, those aren't allegro resources, they're yours resources, you created them, not allegro.

Of course. I meant resources managed with allegro i.e. bitmaps/sounds/etc.

Felipe Maia
Quote:

1. exit() might be called at various places.

If you call exit(), the memory will be freed anyway, there's no need for that.

BAF
Quote:

Can't you call the cleanup function before your program ends? Or can you not add with atexit a cleanup function?

Instead of allegro_init, use install_allegro and pass null for atexit. Then add your atexit handler and at the end of that, call allegro_exit().

Kitty Cat
Quote:

If you call exit(), the memory will be freed anyway

Do not assume this. Even if the OS frees your process's memory (which it's not required to do) it may have system resources allocated, which aren't gauranteed to be freed when a process is closed, because other processes may be able to use it too.

EDIT:

Quote:

Instead of allegro_init, use install_allegro and pass null for atexit.

You can't do that. IIRC, you must pass a valid atexit handler. What's so bad about making sure you don't do Allegro cleanup code in a destructor called after allegro_exit? It's not hard. Register your own atexit handler after allegro_init that delete's what you new, and all is well.

Evert
Quote:

Even if the OS frees your process's memory (which it's not required to do) it may have system resources allocated, which aren't gauranteed to be freed

A good example of this would be video bitmaps in Windows. I understand that this is better now, but it used to be so that these weren't released automatically.

Thread #586425. Printed from Allegro.cc