delete, operator delete() and NULL pointers
In C++ both delete
or, more precisely, the delete expression and operator delete()
can be called with a NULL pointer. The standard requires that such a call shall have no effect. There is, however, a subtle difference in how these two cases are handled under the hood which can be useful to know, especially when writing performance-critical applications.
When we deallocate a memory block using the delete expression, the compiler inserts a check for NULL before calling the destructor and operator delete()
. Consider the following code fragment as an example:
buffer::~buffer () { delete[] buf_; }
During compilation this code snippet is transformed to something along these lines (there is no destructor call because, presumably, buf_
is declared as char*
):
buffer::~buffer () { if (buf_) operator delete[] (buf_); }
Consider now an alternative implementation of the buffer destructor (here we assume that the constructor was also changed to use operator new(n)
instead of new char[n]
):
buffer::~buffer () { operator delete (buf_); }
In this case nothing extra is inserted by the compiler and the check for NULL is performed by the implementation of operator delete()
. Here is the default implementation of this operator provided by g++:
void operator delete (void* ptr) throw () { if (ptr) std::free (ptr); }
As you can see, both alternatives ignore NULL pointers. However, the delete expression checks the pointer before calling the deallocation operator while with operator delete()
, the function call is made unconditionally and the pointer is checked inside the implementation. If such a call is on a critical path and the pointer is frequently NULL (e.g., a buffer is left empty), then checking for NULL before calling operator delete()
can make a difference.
December 8th, 2008 at 10:37 am
Hi Boris,
I found your blog today, I was looking for information about rvalue references. I will study your two posts about them, but in the meanwhile I would like to ask you a question about this post.
First of all, the conclusion appears to me that it’s better to use the first form (delete expression) rather than the second (operator delete): by checking earlier we avoid the unneeded call. Am I right?
The second question is more general: How can you obtain a reliable measure if this subtle modification really makes a difference in an existing program? This is not something that you can test with a simple snippet. What kind of profiling tool/technique do you suggest for such a measurement?
Thanks in advance,
Francesco
December 8th, 2008 at 10:39 pm
Francesco,
You can use one either depending on the semantics of the code. If you are allocating a “type-less” memory block then using operator new()/delete() might be a good idea to convey this. On the other hand, if you are allocating an array of some objects then using the new/delete expressions is a more straightforward way. In some cases, like in the buffer example above, you can reasonably use either one.
As for how to detect the performance penalty, one would normally use a profiler. I use oprofile on GNU/Linux. If operator delete() is called very often, the profiler output will show that. The point in knowing the difference between the delete-expression and operator delete() before profiling is that you may be implementing a library, for example a memory buffer, that other applications will use. And you cannot predict what other applications will do with it. Some may construct and destroy a lot of empty buffers.
Boris