Monday, May 7, 2012

In praise of idleness

C has some odd baggage in its APIs, but one API which I think ought to be emulated more often is free(). Specifically, free(NULL).

Many programmers don't realize that you can pass a NULL pointer to free() and that this has no effect. This isn't undefined behaviour. It's specified to work like that: If ptr is a null pointer, no action shall occur.

This makes cleanup code simpler. Instead of
  if (ptr != NULL) free(ptr);
you can just use
  free(ptr);

This has a number of advantages.

First of all, it reduces the amount of code you need to write for mundane housekeeping tasks.

Secondly, it encourages good habits (freeing memory when you're done with it) by not punishing programmers for using it. If free() crashed when called with a NULL pointer (or worse, corrupted memory) that would discourage programmers from using it. While it doesn't really reward you for writing good code, at least it doesn't kick you in the shin.

Finally, it's consistent with an unfortunate misfeature of its companion, malloc(). malloc(0) is permitted to return NULL. At least you can always pass the result of malloc() to free().

Unfortunately, many other common APIs don't follow free()'s good example. close(-1) and pthread_mutex_destroy(NULL) both invoke undefined behaviour, for example. (And don't get me started about zero as a legal file descriptor!)

Whenever I'm designing my own APIs which include destructor-style functions, I always try to make sure that they quietly ignore NULL. It just makes life simpler for users.