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:
1 | int on_page = 0; |
2 | |
3 | BITMAP *active_page; |
4 | BITMAP *page[3]; |
5 | |
6 | ... |
7 | |
8 | page[0] = create_video_bitmap(SCREEN_W, SCREEN_H); |
9 | page[1] = create_video_bitmap(SCREEN_W, SCREEN_H); |
10 | page[2] = create_video_bitmap(SCREEN_W, SCREEN_H); |
11 | |
12 | active_page = page[0]; |
13 | |
14 | ... |
15 | |
16 | on_page = (on_page + 1) % 3; |
17 | active_page = page[on_page]; |
18 | |
19 | ... |
20 | |
21 | destroy_bitmap(page[0]); |
22 | destroy_bitmap(page[1]); |
23 | destroy_bitmap(page[2]); |
Then all drawing is done to active page. I'm not supposed to call destroy_bitmap for active_page, right?
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.
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.
Destroying a non-existent bitmap will usually result in a crash.
IIRC destroy_bitmap() doesn't crash on NULL...
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.
IIRC destroy_bitmap() doesn't crash on NULL...
Most people don't NULL their stuff.
[edit]
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.
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?
Is there any reason that a bitmap should not be destroyed?
What you allocate, you should free as well.
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.
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.
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.
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).
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?
Most people don't NULL their stuff.
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.
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); }
Right, that's what I'm talking about. Guess I was misunderstood earlier in the thread.
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.
It's early. I'm not awake yet. Sue me. Regardless, the advice is valid.
Aren't global uninitialised variables (including Bitmaps) set to NULL? I thought only local variables could hold any value.
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?
Does allegro destroy its bitmaps automatically on exit?
No.
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?
Can't you call the cleanup function before your program ends? Or can you not add with atexit a cleanup function?
Aren't global uninitialised variables (including Bitmaps) set to NULL?
it is not quaranteed. I think GCC does that only in debug mode
I thought only local variables could hold any value.
huh?
As for cleaning up on program exit, I would simply do something like this:
1 | Object *bunc, *of, *globals; |
2 | |
3 | void init(){ |
4 | intAllegro(); |
5 | initGlobalObjects(); |
6 | } |
7 | void run(){ |
8 | while (gameGoesOn){ |
9 | doStuff(); |
10 | } |
11 | } |
12 | void exit(){ |
13 | freeGlobalObjects(); |
14 | } |
15 | |
16 | int main(){ |
17 | init(); |
18 | run(); |
19 | exit(); |
20 | } |
21 | END_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.
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?
Thinking logically, yes you have to destroy them yourself because you created them.
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.
Yes
[edit]late
but i add this:
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.
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.
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()).
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.
Why would you want to explictly call set_gfx_mode(); to destroy the screen? Does it destroy every bitmap as well?
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.
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.
1. exit() might be called at various places.
If you call exit(), the memory will be freed anyway, there's no need for that.
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().
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:
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.
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.