root said:
I ask because I'm designing a library at the moment. There's a struct
type that has a couple integer fields and a couple pointer fields.
There's a mystruct_init() function that populates the fields, including
making the pointers point to something dynamically allocated.
So what to do if malloc() fails? It's a library, so printing an error
(or still worse abort()ing) is out of the question. One possibility is
to ask the caller to check each of the pointers inside the struct to see
whether they're NULL each time it inits() a mystruct. But that doesn't
seem very friendly, and various mystruct_...() functions might realloc()
the pointers so this would become complex for calling code and generally
scale badly.
The situation seems comparable to mpz_t, in that although in theory the
amount of memory needed could be very large, in practise it will almost
always only be perhaps enough for a couple dozen pointers-to-int. So if
GMP can get away with ignoring allocation failure, maybe I can too - is
what I was thinking/hoping.
There's no easy answer.
The default should be to return a NULL pointer or similar failure to the
caller. This has the disadvantage that the program is stuffed with
error-handling code that will never be called.
If the amount of memory asked for is small you've got to ask "how likely is
a failure" and "what does a failure mean?". If, for instance, the chance of
an allocation failure is statisitically less than the chance of the computer
breaking down, you could argue that you are justified in ignoring it. If
realistically the program cannot continue if the system is refusing to give
it a few bytes, you could argue that you might as well terminate now rather
than in calling code.
The problem is that often callers do want to recover from errors, for
instance permitting the user to save. That raises a whole host of other
issues - often it is better not to save at all rather than save a corrupt
state - but as library writer you cannot handle them.
The other alternative is to write a wrapper to malloc() that never fails. If
memory is exhausted, it asks the user for more memory, looping until user
either complies or takes other action against the program. The snag is that
C has no usable user IO to make this function practical to be written
portably, unless you allow the caller to specify a nag function. That adds a
lot of complexity to your library interface.