simply checking for NULL doesn't allow that - for example for something that might have been opened with fopen() needs to be closed with fclose() rather than free(), and you can't tell that from the pointer.
void my_thing_free(MyThing *thing) {
fclose(thing->file);
free(thing);
}
assuming an associated "my_thing_new" that only returns a valid pointer when both the allocation and the fopen succeeded.