Malcolm McLean said:
This approach is a blind alley. As you add members to logic to free
and abort becomes more and more complicated.
That arguments sounds like "it is going to get messy do lets start
messy". I'd prefer to solve today's problem and re-organise[1] *if*
required tomorrow -- the design version of avoiding premature
optimisation. However...
It is a lot better to
have a "clean up and return" section that is quite clearly not part of
normal execution.
In fact, that is pretty much what I have. It is the else. I think the
key thing is to ensure that all pointers are either NULL or malloc'ed
at the key times. calloc is not required to return storage
initialised to something that compares == to a null pointer constant,
so a bit more work is needed when the space has more than one pointer,
but it scales to more than one just fine:
struct big_sample *bsp = malloc(sizeof *bsp);
if (bsp) {
*bsp = (struct big_sample){0};
if ((bsp->ptr1 = malloc(src->sz1)) &&
(bsp->ptr2 = malloc(src->sz2)) &&
(bsp->ptr3 = malloc(src->sz3)) &&
(bsp->ptr4 = malloc(src->sz4))) {
/* all good to go now */
memcpy(bsp->ptr1, src->ptr1, src->sz1);
memcpy(bsp->ptr2, src->ptr2, src->sz2);
memcpy(bsp->ptr3, src->ptr3, src->sz3);
memcpy(bsp->ptr4, src->ptr4, src->sz4);
}
else {
free(bsp->ptr1);
free(bsp->ptr2);
free(bsp->ptr3);
free(bsp->ptr4);
free(bsp);
bsp = NULL;
}
}
return bsp;
so you get a bump from one if to two when you go from the common case
of one dependent thing to more than one, but it scales just fine.
Obviously, with this much regularity one would be using an array -- I
just kept the pattern simple so you could see how it scales. In a
real messy case, all the mallocs, sizes and memcpys would be different
and quirky.
The problem isthat for such a simple structure you are right. Add
another array and you've got to have a curly brace anyway. Get into
the habit of
void killme(MYSTRUCT *ptr)
{
if(ptr)
{
}
}
It is a matter of taste to some extent. If that were the "house
style" I'd use it, but I prefer minimal braces myself. I can't see:
if (sp)
free(sp->p1);
free(sp->p2);
free(sp);
(which is how the error would look) without a big alarm going off --
I'm getting a funny feeling just letting it sit there on the screen
now. For me, C's { }s are HUGE -- maybe from learning LISP so long
ago.