I understand that if you try to use free() on a location that has 'already' been freed, this can lead to memory leaks. However, I'm curious to know if the same applies to Allegro's destroy_bitmap() function. Is it safe for my program to run that function on a location that is not allocated?
No, it's not safe.
The problem with double free() is not with memory leaking, but crashes.
Best case in a well-behaving environment double-freeing doesn't cause memory leaks - it's FATAL.
Worst case in a misbehaving environment, double-freeing is "undefined behavior", which can be even worse than fatal.
destroy_bitmap() involves a free() operation, so, you do the math
I think calling free/destroy_bitmap on null pointers is safe. That means, every time you free some memory or delete a bitmap, set it's pointer to null.
if the pointer is null then destroy_bitmap returns without doing anything. this then means if you have an unitialised pointer variable with some arbitrary random number then call destroy_bitmap will do bad things. Snippet from destroy_bitmap:
void destroy_bitmap(BITMAP *bitmap) { if (bitmap) { ...stuff free(bitmap); } }
Yes - but there's a big difference between a NULL pointer -
BITMAP* bmp = 0; destroy_bitmap( bmp );
and an already freed ptr -
BITMAP* bmp = load_bitmap( "somebitmap.bmp" ); destroy_bitmap( bmp ); destroy_bitmap( bmp );
Doing this will crash yuh.
Yes, that's what I said. If you free a pointer, it doesn't automatically give itself a value of 0. If you code properly, as in ensuring your pointers are either valid or null:
BITMAP* bmp=NULL;
...
...
destroy_bitmap(bmp);
bmp=NULL;
Then all will be well.
Does "delete" have the same behaviour? I use it without any checks:o
delete has the same behaviour. Always set them to NULL after you delete them, if you plan to use them again.
If I remember correctly then NULL has been deprecated and regular 0 should be used instead. I don't remember if this is only in C++ or in C too though.
The macro NULL is an implementationdefined
C++ null pointer constant in this International Standard
(4.10). Possible definitions include 0 and 0L, but not (void*)0.
Not the newest source, I admit.
If I remember correctly then NULL has been deprecated
Then why did you use it to begin with anyway?
See your first post
MSVC 8 complains about a lot of things being deprecated. itoa(), sprintf(), _snprintf(), and more. It does not complain about NULL. If it is deprecated, google doesn't favour the pages that explain it.
In C, 0 is not NULL. In C++, NULL is defined as 0. It just makes more sense to use NULL (I want a null pointer, not zero).
Then why did you use it to begin with anyway?
How to you spell "0"? I know it can be written as "zero" or "null", possibly something else too
MSVC 8 complains about a lot of things being deprecated.
As I've heard it does. As it doesn't like standards a lot then I'm not suprised it doesn't do anything about the NULL macro. Though I'm not sure if any other compilers do.
In C, 0 is not NULL.
But it has to be something that evaluates to 0. If it doesn't it might be a bit difficult to use in conditionals like if (blah) bleh();
I found this in MinGW/stddef.h:
#define NULL __null
I tried adding this to my prog:
#define __null 0
It doesn't complain but this is also weird. Then what is "__null"? (or what was:))
I believe it is (void*)0 in C. Could be wrong.
How to you spell "0"? I know it can be written as "zero" or "null", possibly something else too
It's a case sensitive argument?
Probably some kind of compiler extension.
Why can't I get this thing to crash?!
1 | #define msj allegro_message |
2 | #include <allegro.h> |
3 | |
4 | int main() |
5 | { |
6 | allegro_init(); //set_gfx_mode(GFX_TEXT, 0,0,0,0); |
7 | |
8 | int *ptr; |
9 | |
10 | msj("newing"); |
11 | ptr = new int;//[5]; |
12 | msj("newed\n%d", ptr); |
13 | |
14 | delete[] ptr; //delete ptr; |
15 | msj("deleted\n%d", ptr); |
16 | |
17 | delete[] ptr; //delete ptr; |
18 | msj("deleted again\n%d", ptr); |
19 | |
20 | ptr = NULL; |
21 | msj("ptr/NULL = %d", ptr); |
22 | |
23 | ptr += 2; |
24 | msj("ptr_int +2 = %d", ptr); |
25 | |
26 | return 1; |
27 | } END_OF_MAIN() |
`Proper' programming practice (according to some) says that in C++, one should use 0 instead of NULL also for pointers (don't ask me why).
In C, a pointer that is NULL evaluates to the boolean value 0 and an integer of 0 assigned to a pointer will set the pointer to NULL. That said, wether or not NULL is actually 0, (void *)0 or something else entirely is platform dependent.
Why can't I get this thing to crash?!
Because you're relying on undefined behavior. Undefined behavior may mean that your program will work as expected just as well as making your computer burst into flames. You don't know which (or if there is anything in between), and the results don't need to be consistent from run to run.
Murat AYIK:
As Bob already pointed out, "undefined behavior" is just that - undefined. Early when I said "IT IS FATAL" or something like that, my point was twofold. A - it doesn't cause memory leaks as originally claimed, but rather the error would be a fatal fault and B - say something is "FATAL" usually encourages people not to do it
It PROBABLY won't help you get a crash, but also try
if you're trying to demonstrate this bad behavior. But it's also quite possible it won't bite you until you accidentally do it in a complex program
OK, I just wanted to see what would happen during the dying process:)
Also neither new nor the malloc example crashed in MinGW or Turbo C++ 3.0 . Damn compilers! They don't produce miserable executables when you need one:P
So using zero or a #define trick would be safe, right?
Destroying a previously freed bitmap will probably end in segmentation fault, definately under Win2k and XP. This should work:
DATAFILE *gfx; BITMAP *bmp; gfx = load_datafile("blah.dat"); bmp = (BITMAP *)gfx[OBJECT].dat; unload_datafile(gfx); destroy_bitmap(bmp); // at this point it will die by horrible death