Jonathan Boccara's blog

How to Make Custom Deleters More Expressive

Published September 1, 2017 - 3 Comments

Daily C++

Most of the times where we use std::unique_ptr, we’re fine without using a custom deleter. But sometimes, a custom deleter offers a way out of a tricky situation.

Now that we’ve seen how to use custom deleters and when they can be useful, I would like to share with you a technique to make their usage more expressive that our regular reader Sergio Adán showed, in reaction to the previous article.

When I read it I slapped my forehead and went “why didn’t I code like this, each time I used a custom deleter??” Let’s see what this is about.

Custom deleters are ugly

Like we saw in Smart developers use smart pointers (ep 3), to set a deleter into a unique_ptr requires adding a function type in the unique_ptr, and the underlying pointer had better be const. For example, with the type Computer:

But this is dense enough that looking at it too long is dangerous for your eyes. Spreading such an expression across production code is out of the question. So the natural way to go about this is to write an alias:

which fares better in an interface:

But the ugliness is still there when we create new instances of the unique_ptr because we have to pass a deleter each time:

Where we defined deleters:

This poses three issues. The first one is that we shouldn’t have to specify anything in the case where we want the smart pointer to delete its resource. It’s what smart pointers are made for in the first place.

Granted, this one it particular because it could have to not delete its resource for some occurrences. But why would the nominal case of deleting it be burdened because of the special case?

The second issue appears with namespaces, and comes down to plain ugliness. Imagine that our Computer type was inside a nested namespace, like often in production code:

And then at call site:

This is a tough line of code. And for saying so little.

The last issue is that we define a delete and a doNotDelete function for each type on which we want to custom deleters. And even if their implementation has nothing specific to the type Computer, or any other type. However, note that even templating the deleters this way:

…doesn’t make the code lighter. Indeed, we still need to specify the template type when instantiating the pointer:

A unique interface

Now here is what Sergio suggested, and that can fix the two above issues: use the same interface for all custom deleters on all types.

This can be defined in another namespace, a technical one. Let’s call this namespace util for the example. (I’ll use a slightly modified version of the comment’s initial code.)

Then in this namespace, we write all the common code that creates the custom unique_ptr. Let’s call this helper MakeConstUnique for instance. Here is all its code:

With this code, no need to define anything else to start using a unique_ptr on a particular type with custom deleters. For instance, to create an instance of a unique_ptr that does a delete of its resource when it gets out of scope, we write:

And to create one that does not delete its resource:

What is interesting about this interface is that:

  • there is no longer any mention of delete in the nominal case,
  • we can now use auto, thanks to the return type of MakeConstUnique.

Note that all this made us go down to one occurrence of the namespace of Computer, when we started with three:

Specific deleters

Now what if, for some reason, we didn’t want to call delete on the class Computer, but a particular dedicated function? This can happen in types coming from C for example (but not only):

To keep using MakeConstUnique with this type, we can totally specialize this template function for the type Computer. We could do this in the module defining Computer, by reopening the util namespace:

In this case, the client code probably doesn’t allocate its pointer with new either.

Whichever way, a resource gets to be disposed of

Let’s now test our interface, by adding a bit of logging in the Computer class:

And let’s pass both a resource on the heap and a resource on the stack to our interface:

When run this code outputs:

A big thank you to Sergio for sharing this idea, that helps making custom deleters more expressive. And if, like Sergio, you want to react to something you read on Fluent C++, I’d love to hear what you have to say!

Related article:

Liked it ? Share this post ! Facebooktwittergoogle_plus    Don't want to miss out ? Follow:   twitterrss

Receive regular updates to make your code more expressive.