Using std::unique_ptr With C APIs

Most people think of std::unique_ptr as a smart pointer type that helps manage calls to new and delete in an RAII-safe manner. This is true, and most of the time this is what I use std::unique_ptr for. However something that I think is less well known is that std::unique_ptr can destruct the owned pointer using a custom deleter type, which lets you dealloate the resource using a mechanism other than the C++ delete operator.

An idiom I find particularly handy is using std::unique_ptr to automatically calling std::fclose on an owned FILE*. Here's how you do it:

// Second argument is a pointer to the type of std::fclose, we could also have
// written it out explicitly as std::unique_ptr<FILE, int (*)(FILE*)>.
using FilePtr = std::unique_ptr<FILE, decltype(std::fclose) *>;

// Instantiate the FILE* with the destructor we want.
FilePtr file(std::fopen(filename, "rbe"), std::fclose);

// Do stuff with the file
std::fread(buf_.data(), 1, buf_.size(), file.get());

Now when the file goes out of scope std::fclose() will automatically be called by the destructor.

You can also use this when interacting with C APIs that have init/destroy methods (which is probably most C APIs). For example, suppose you're using xxHash from C++. Normally you'd write code like:

XXH3_state_t *state = XX3_createState();
// Do stuff with state ...
XXH3_freeState(state);

If you want to do this safely you might be tempted to create a small wrapper class or struct that manages a HHX3_state_t* and calls XXH3_freeState in the destructor. But if this is all you want to do, you can also just use std::unique_ptr with a custom deleter:

using XXH3StatePtr = std::unique_ptr<XXH3_state_t, decltype(XX3_freeState) *>;
XXH3StatePtr state(XXH3_createState(), XXh3_freeState);
// Do stuff with state ...

If you're interfacing with a complicated C API that has a lot of methods it might be useful to create wrapper classes to provide a full OO API. But if you just want to do something really simple, this technique may be simpler.