IS this a proper way of freeing memory with free()

R

Richard Heathfield

Yevgen Muntyan said:
You snipped the piece where I said when I need to.

There is no need to cast malloc, even in a macro.

The same "simple solution" as was offered elsewhere: avoid
situations where you need cast and you will not need cast.
But I still believe that

#define ALLOC_A_THING(Type) ((Type*) malloc (sizeof (Type)))

is not too bad.

It's ghastly. It doesn't buy you anything useful. It doesn't encapsulate
anything worth encapsulating.
 
I

Ian Collins

matevzb said:
No, it won't in case of void *. A hypothetical case:

If "ptr" in main() is changed from "long *" to "short *", there will
be no warning (and no casts were used). There will be a bug lurking
however.

If you lie to the compiler, what do you expect?
 
Y

Yevgen Muntyan

Richard said:
Yevgen Muntyan said:


There is no need to cast malloc, even in a macro.



It's ghastly. It doesn't buy you anything useful. It doesn't encapsulate
anything worth encapsulating.

#define ALLOC_A_THING(Type) ((Type*) custom_allocator_here (sizeof (Type)))

Even with malloc this macro is more convenient than malloc(sizeof *foo)
or malloc(sizeof(Foo)) (given the name is better than
"custom_allocator_here"). Some people even believe it's safer than
raw malloc. Or

#define FOO_NEW() ((Foo*) malloc (sizeof (Foo))) // *must* cast here

Regards,
Yevgen
 
R

Richard Heathfield

Yevgen Muntyan said:
#define ALLOC_A_THING(Type) ((Type*) custom_allocator_here (sizeof
#(Type)))

Even with malloc this macro is more convenient than malloc(sizeof
*foo) or malloc(sizeof(Foo)) (given the name is better than
"custom_allocator_here").

I fail to see why:

p = ALLOC_A_THING(foo);

is more convenient than:

p = malloc(sizeof *p);
Some people even believe it's safer than raw malloc.

Some people even believe Elvis lives.
Or

#define FOO_NEW() ((Foo*) malloc (sizeof (Foo))) // *must* cast here

Why? The cast doesn't do any good, and in any case this is a lousy way
to create an object of a particular type. You'd be far better off with
a function that could not only reserve storage for the object but also
populate it with its initial value.
 
Y

Yevgen Muntyan

Richard said:
Yevgen Muntyan said:


I fail to see why:

p = ALLOC_A_THING(foo);

is more convenient than:

p = malloc(sizeof *p);

You fail to see, I don't. I like ALLOC_A_THING because
it describes the intent and hides the actual memory
allocation. Anyway, let it be not convenient. How
about custom_allocator_here() function?

Here's real code example.

MooClosure *moo_closure_alloc (gsize size,
MooClosureCall call,
MooClosureDestroy destroy);
#define moo_closure_new(Type__,call__,destroy__) \
((Type__*)moo_closure_alloc (sizeof(Type__), call__, destroy__))

Equivalent effect if moo_closure_alloc returns void*.
Why? The cast doesn't do any good,

It saves your butt if you change type, the famous "why you shall do
malloc(sizeof *ptr)" thing, you know.
and in any case this is a lousy way
to create an object of a particular type. You'd be far better off with
a function that could not only reserve storage for the object but also
populate it with its initial value.

Sure, malloc() there is silly. Custom allocation function which does
more than calling malloc is much more realistic. See the above macro.
Now you can tell it's possible to avoid anything of that sort. Of
course it is.

Yevgen
 
K

Keith Thompson

Yevgen Muntyan said:
Mark McIntyre wrote: [...]
If you're compiling it with a C++ compiler, its C++ code. It may look
like C, it may also compile as C, but its C++, and probably badly
written C++ at that.

Okay, let's use this term: "C code which is intended to be compiled
both with C and C++ compilers". I mean "C code" by "C code", i.e.
the code which is C according to C standard and is compilable with
C compiler in conforming mode. Not sure it's strict enough, but hope
you get the idea (which you already got anyway, I believe).
And no, C code doesn't become C++ code because you feed it to g++, even
if C++ folks think it is :)

No, C code doesn't become C++ code because you feed it to g++. If g++
accepts it (assuming g++ to be a correctly working C++ compiler), then
it was *already* C++ code.

What you're talking about is code that is simultaneously C code and
C++ code.

I don't want to get too deeply into this argument, but I will say
that, in my opinion, there is rarely a real need to write such code.
(I said "rarely", not "never".)
 
B

Bill Pursell

No, it won't in case of void *. A hypothetical case:
#include <stdlib.h>
#include <string.h>

typedef enum
{
SHORT = 0,
LONG = 1
} mytype;

int
fcn (void *array, mytype type, size_t size)
{
void *ptr;

switch (type)
{
case SHORT:
ptr = malloc (size * sizeof(short));
memcpy (ptr, array, size * sizeof(short));
break;

case LONG:
ptr = malloc (size * sizeof(long));
memcpy (ptr, array, size * sizeof(long));
break;

default:
return -1;
}

return 0;
}

int
main (void)
{
long *ptr = malloc (10 * sizeof *ptr);

memset (ptr, 1, 10 * sizeof *ptr);
fcn (ptr, LONG, 10);

return 0;
}

If "ptr" in main() is changed from "long *" to "short *", there will
be no warning (and no casts were used). There will be a bug lurking
however.

This bug is caused by a design flaw in fcn. Change the
prototype so that the call is fcn(ptr, sizeof *ptr, 10) and
the problem is gone. Be in the habit of casting malloc
and hand editing your entire code base whenever you
change a type, and you will probably not notice the
design flaw. Be in the habit of not casting malloc and
not editing your code base regularly, and the design
flaw will be obvious early.
 
Y

Yevgen Muntyan

Keith said:
Yevgen Muntyan said:
Mark McIntyre wrote: [...]
If you're compiling it with a C++ compiler, its C++ code. It may look
like C, it may also compile as C, but its C++, and probably badly
written C++ at that.
Okay, let's use this term: "C code which is intended to be compiled
both with C and C++ compilers". I mean "C code" by "C code", i.e.
the code which is C according to C standard and is compilable with
C compiler in conforming mode. Not sure it's strict enough, but hope
you get the idea (which you already got anyway, I believe).
And no, C code doesn't become C++ code because you feed it to g++, even
if C++ folks think it is :)

No, C code doesn't become C++ code because you feed it to g++. If g++
accepts it (assuming g++ to be a correctly working C++ compiler), then
it was *already* C++ code.

What you're talking about is code that is simultaneously C code and
C++ code.
Yes.

I don't want to get too deeply into this argument, but I will say
that, in my opinion, there is rarely a real need to write such code.
(I said "rarely", not "never".)

And this is the key point: "rarely" is not "never".
Though it's not really that rare, just look at /usr/include/*.h or
whatever_path\include\*.h. Lots of C code which is
intentionally made C++-compatible. Lately only die-hard
hate-c-plus-plus folks make public C headers not C++-compatible
if they want their libraries to be used. I indeed was
talking not about this (except the parts about headers
of course). I did talk about doing "g++ foo.c". Anyway,
nobody is really talking about technical stuff. Technical
stuff is used in this discussion to justify blind stupid
"Wrong period". Whatever.

Yevgen
 
C

CBFalconer

CBFalconer said:
Damn. I could have sworn I read stdio there. There goes my
perfect record. The nits are getting out of hand.

I have to revise that. Obviously I slipped into an alternate
universe, which explains the substitution of stdlib for stdio, and
preseves my impeccable record.

--
<http://www.cs.auckland.ac.nz/~pgut001/pubs/vista_cost.txt>
<http://www.securityfocus.com/columnists/423>

"A man who is right every time is not likely to do very much."
-- Francis Crick, co-discover of DNA
"There is nothing more amazing than stupidity in action."
-- Thomas Matthews
 
R

Richard Heathfield

Yevgen Muntyan said:
Richard Heathfield wrote:

You fail to see, I don't. I like ALLOC_A_THING because
it describes the intent and hides the actual memory
allocation.

No, it doesn't, at least no more than malloc does. And even if it did,
which it doesn't, you still don't need the cast.
How
about custom_allocator_here() function?

Yeah, you wouldn't need a cast there either.

It saves your butt if you change type,

So let me get this straight - you're saying that if you're daft enough
to use the type in the sizeof, you have to write some otherwise
unnecessary code to give the compiler a fighting chance of warning you
about your daft decision, and only at the risk of suppressing another
warning about your daft decision? Yeah, that's true - constructing
daftness is not difficult in C, or in any language. So?
 
R

Richard Heathfield

Yevgen Muntyan said:

It's easy to write lot of C code which is valid C++. You have to
apply casts to return value of malloc though.

It's *pointless* to write lots of C code which is valid C++. If you
can't take advantage of C++'s non-C features, why bother using it? And
if you can, then it's not compilable in C. And malloc makes for bad C++
programs, on the whole.
Okay, let's use this term: "C code which is intended to be compiled
both with C and C++ compilers".

Ah, you mean "bad code" (unless your name is P J Plauger, which it
isn't).
I mean "C code" by "C code", i.e.
the code which is C according to C standard and is compilable with
C compiler in conforming mode. Not sure it's strict enough, but hope
you get the idea (which you already got anyway, I believe).
And no, C code doesn't become C++ code because you feed it to g++,
even if C++ folks think it is :)

Right. Instead, if it's a *good* C program, it becomes a raw material
which the compiler uses to produce diagnostic messages. If it's a bad
or trivial C program, it might also be a valid C++ program. Such
multi-language programs are few and far between, but they do exist.
 
R

Richard Bos

Yevgen Muntyan said:
It's easy to write lot of C code which is valid C++. You have to
apply casts to return value of malloc though.

That's what Mark said: sloppy.

Richard
 
R

Richard Bos

matevzb said:
No, it won't in case of void *. A hypothetical case:
#include <stdlib.h>
#include <string.h>

typedef enum
{
SHORT = 0,
LONG = 1
} mytype;

int
fcn (void *array, mytype type, size_t size)
{
void *ptr;

switch (type)
{
case SHORT:
ptr = malloc (size * sizeof(short));

You didn't read the construct you're criticising, did you? You didn't
even read the reason why that construct is better, because here you're
demonstrating exactly why it is better than this code.

Again:

ptr=malloc(num * sizeof *ptr);

is always less likely to break than

ptr=malloc(num * sizeof(type));

If you choose to break that by using void * for everything and then
casting to random types, that's your problem, and it demonstrates
exactly nothing about the need to check anything in well-written C.

Richard
 
I

Ian Collins

Richard said:
Yevgen Muntyan said:




It's *pointless* to write lots of C code which is valid C++. If you
can't take advantage of C++'s non-C features, why bother using it? And
if you can, then it's not compilable in C. And malloc makes for bad C++
programs, on the whole.
It's not pointless if you are using C++ for hardware simulations to test
your C drivers.
 
R

Richard Heathfield

Ian Collins said:
It's not pointless if you are using C++ for hardware simulations to
test your C drivers.

If you're using C++ for the hardware simulations, you're using C++, not
C.
 
R

Richard Heathfield

Ian Collins said:
Richard said:
Ian Collins said:
Richard Heathfield wrote:
Yevgen Muntyan said:

It's easy to write lot of C code which is valid C++. You have to
apply casts to return value of malloc though.

It's *pointless* to write lots of C code which is valid C++. [...]

It's not pointless if you are using C++ for hardware simulations to
test your C drivers.

If you're using C++ for the hardware simulations, you're using C++,
not C.
The driver code is C.

Fine, in which case it isn't C++, so you don't need the cast on malloc.
 
M

matevzb

This bug is caused by a design flaw in fcn. Change the
prototype so that the call is fcn(ptr, sizeof *ptr, 10) and
the problem is gone. Be in the habit of casting malloc
and hand editing your entire code base whenever you
change a type, and you will probably not notice the
design flaw. Be in the habit of not casting malloc and
not editing your code base regularly, and the design
flaw will be obvious early.
You could put it that way. Unfortunately, I have to use a function
very similar to the abovementioned fcn() and it's part of an external
library on which I have no influence whatsoever (the function is used
for packing parameters for RPC calls). I don't use any unnecessary
casts, but using sizeof *ptr brings me no benefits. Perhaps it's a
design flaw, but I prefer to call it reality.
 
M

matevzb

You didn't read the construct you're criticising, did you? You didn't
even read the reason why that construct is better, because here you're
demonstrating exactly why it is better than this code.

Again:

ptr=malloc(num * sizeof *ptr);

is always less likely to break than

ptr=malloc(num * sizeof(type));

If you choose to break that by using void * for everything and then
casting to random types, that's your problem, and it demonstrates
exactly nothing about the need to check anything in well-written C.
It's not my choice, see the reply to Bill Pursell. And of course it's
my problem, I have to use such code, be it well-written C or not.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,262
Messages
2,571,059
Members
48,769
Latest member
Clifft

Latest Threads

Top