I know that calling free with a null pointer is a NO-OP, free already has a check for that, but it's also true that free is a libc library function that might have some fixed overhead respect to doing nothing.
My question is, is it worth to consider replacing this:
delete ptr;
by this?
if (ptr)
delete ptr;
First, do delete do a null check before forwarding the call to free? or do delete usually forwards the call in an absolutely transparent way?
If that's the case, we can talk in terms of free from now on.
So, is the transformation above worth it in order to avoid a potentially expensive free execution that does nothing? In C++ it might be a thing to consider because of std::moveing objects around might leave a graveyard of empty objects behind while reaching to its final destination; objects whose destructors will call free with null pointers.
Checking the glibc source code, I found this:
void
free (void *ptr)
{
struct header *real;
/* Determine real implementation if not already happened. */
if (__glibc_unlikely (initialized <= 0))
{
if (initialized == -1)
return;
me ();
}
/* If this is not the correct program just use the normal function. */
if (not_me)
{
(*freep) (ptr);
return;
}
/* `free (NULL)' has no effect. */
if (ptr == NULL)
{
catomic_increment (&calls[idx_free]);
return;
}
// rest of the implementation
so calling it looks like not "free" at all; there's stuff below and even an atomic increment before the null check, but it's also true that this implementation might be a fallback implementation or something; that's not the first time I'm reading a library function whose actual implementation is done somewhere else, in assembly or something, or there's specialized versions for different archs or whatever.
deletenever directly callsfree.deletecalls some deallocation function, i.e. some function with nameoperator delete. The global replaceableoperator deleteoverloads have a library implementation that in some suitable way deallocate memory obtained by the correspondingoperator new. There is no guarantee that it will usefreefor this or how it will usefree.The global
::operator delete(void*)is replaceable in any translation unit. Therefore the compiler is not able to see through it or inline it.Generally a
deleteexpression must always implicitly do a null pointer check anyway, because if a null pointer is passed, then no destructor may be called. If the destructor is trivial or the compiler can inline it to see that it won't do anything, then of course this implicit check might be optimized away.Whether or not the deallocation function will be called if a null pointer is provided is up to the compiler. So it may or may not be that the compiler performs an implicit null pointer check before calling the deallocation function regardless of your explicit one.
A quick test on godbolt suggests to me that at least both GCC and Clang always emit an implicit null pointer check before calling the deallocation function anyway. So your added explicit check can't positively affect performance.