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.

2 Responses to “delete, operator delete() and NULL pointers”

  1. Francesco Says:

    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

  2. Boris Kolpackov Says:

    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