On 05/24/2012 06:05 PM, Robert Wessel wrote:
> On Thu, 24 May 2012 13:05:52 -0400, James Kuyper
> <
james...@verizon.net> wrote:
>
>> On 05/24/2012 12:31 PM, Robert Wessel wrote:
>>> On Thu, 24 May 2012 12:15:16 +0200, Dirk Zabel <
za...@riccius-sohn.eu>
>>> wrote:
...
It's equally trivial to notice that pp and qq don't match; they're both
part of the same assignment expression. When used in the initialization
of a pointer, CNEW() is equally easy to check. However, in the common
case where a pointer is being set somewhere other than during
initialization, if an error message is triggered, figuring out the right
type requires searching elsewhere:
pp = CNEW(pear); // Is pp a pear*, or a kumquat*?
When the object whose value is being set is foo->bar->baz, finding out
the type pointed at could require searching through a string of header
files; with the clc idiom, getting it right can be done just by looking
at a single assignment expression.
> The standard idiom also does not help usages which do not involve
> immediate assignments to a pointer. Consider:
>
> int f(pear *pp);
> ...
> f(CNEW(pear)); /* safe */
> f(malloc(...)); /* not so much */
The clc idiom is inapplicable to that case - it requires a pointer
expression as an argument of sizeof. CNEW() is not particularly
objectionable in that case, but I would consider it a rare one. I
generally want to do something more like the following:
pp = malloc(sizeof *pp);
if(pp)
f(pp);
else
{
// Error handling
}
Actually, normally, what would be the if-branch in the above code
usually contains a lot more than single function call. I prefer to keep
error handling close to the function call whose failure triggered the
handling, so I would usually reverse the test:
pp = malloc(sizeof *pp);
if(pp == NULL)
{
// Error handling
}
else
{
if(f(pp)!=SUCCESS)
{
// Error handling
}
else
{
// Other stuff
}
}
> IMO, as a practice, attaching a type to an object as soon as it's
> created is just good form,
I agree. With either the clc idiom, or CNEW(), the compiler must
generate code implementing the following sequence of events:
1. call malloc()
2. convert the result of that call to pear*
3. store the result of that conversion in pp
There's not a single event separating step 1 from step 2, whether you
use the clc idiom or CNEW(). That's ASAP as far as I'm concerned.
> ... and requiring something to be duplicated
> (correctly) is just asking for trouble, as sooner or later someone is
> going to duplicate and modify a chunk of code and miss one of the
> references.
That's an argument for
#define NEW(pp) (pp) = malloc(sizeof *(pp))
which has already been discussed. The argument of NEW() only needs to be
changed if the variable name changes. The argument of CNEW() needs to be
changed any time the type changes. I might consider using something like
NEW(), but only if I needed to use it very frequently. However, I'd
probably give it a different name, since it's not as closely analogous
to the 'new' operator in C++ as CNEW() is.