Implementing “finally” in C++
Tags: cpp
Published: 2023-05-24 12:43:44

---
title: Implementing “finally” in C++
published: true
description: Implementing “finally” found in other languages in C++.
tags: #cpp
# cover_image: https://direct_url_to_image.jpg
# Use a ratio of 100:42 for best results.
# published_at: 2023-04-28 00:28 +0000
---

## Introduction

In many functions, you want to guarantee that some “clean-up” function is always called regardless of where or how a function returns.  For example, a database class likely will have a `close()` function that _must_ be called when you’re done with a particular database. In Java, this is accomplished with the `finally` keyword: 

```java
public class DB {
    public DB( String db_name ) {
        // ...
    }

    public void close() {
        // ...
    }
}

public class UseDB {
    public static void main( String args[] ) {
        DB db = new DB( "foo" );
        try {
            // ...
        }
        finally {
            db.close();
        }
    }
}
```

The “C++ way” of doing this would be to use a destructor instead:

```cpp
class DB {
public:
    explicit DB( std::string const &db_name );
    ~DB() { close(); }

    void close();
}

int main() {
    DB db{ "foo" };
    // ...
}
```

However, suppose you’re using some C library in C++ that has functions like:

```c
DB*  db_open( char const *db_name );
void db_close( DB *db );
```

In order to guarantee that `db_close()` is always called, you’d need to do:

```cpp
int main() {
    DB *const db = db_open( "foo" );
    try {
        // ...
        db_close( db );
    }
    catch ( ... ) {
        db_close( db );
        throw;
    }
}
```

That is, call `db_close()` in two separate blocks of code since C++ doesn’t have `finally`.

One way to solve this would be to write a C++ wrapper class around the C library.  If it will be used a lot, this is a good approach.  However, if it won’t be used a lot, then writing a full wrapper class might be overkill.

Another way to solve this would be to implement a generic `finally` in C++ so you could do this:

```cpp
int main() {
    DB *const db = db_open( "foo" );
    finally f{ [db]{ db_close( db ); } };
    // ...
}
```

That is, have `finally` be a class whose destructor will run an arbitrary piece of code.  Granted, it doesn’t have the same feel as `finally` in Java, but it works.  It’s actually closer to `defer` in Go.

## Initial Implementation

Here’s a first cut at an implementation of `finally` in C++:

```cpp
template<typename CallableType>
class finally {
public:
    explicit finally( CallableType &&callable ) noexcept :
        _callable{ std::move( callable ) }
    {
    }

    ~finally() noexcept {
        _callable();
    }

private:
    CallableType _callable;
};
```

While this works, it has a number of problems.

## Forbidding Copying

The first problem is that copying a `finally` object will result in the code being run more than once that likely will be the wrong thing to do:

```cpp
finally f1{ [db]{ db_close( db ); } };
finally f2{ f1 };  // will close the same database twice!
```

Fortunately, this is easy to fix by deleting the relevant member functions:

```cpp
    // ...
private:
    CallableType _callable;

    finally( finally const& ) = delete;
    finally( finally&& ) = delete;
    finally& operator=( finally const& ) = delete;
    finally& operator=( finally&& ) = delete;
};
```

## Constraining the Template Type

A less serious problem is what if `CallableType` actually isn’t callable?  What if it’s something like `int`?  The compiler will, of course, print an error message, but it will likely be fairly cryptic and also on a line in the `finally` implementation itself rather than where the user attempted to declare the `finally` object.

Fortunately, this is also easy to fix by using the [`std::invokable`](https://en.cppreference.com/w/cpp/concepts/invocable) concept:

```cpp
template<std::invocable CallableType>
class finally {
    // ...
```

## Allowing Moving

The initial fix of forbidding copying also forbid moving. If we want to allow moving, that’s possible, but it’s a little more involved in that we need to add an `_invoke` flag to know whether we should actually invoke the callable since a move’d-from `finally` _must_ have its `_invoke` flag set to `false`:

```cpp
    // ...
    explicit finally( CallableType &&callable ) noexcept :
        _callable{ std::move( callable ) },
        _invoke{ true }
    {
    }

    finally( finally &&from ) noexcept :
        _callable{ std::move( from._callable ) },
        _invoke{ std::exchange( from._invoke, false ) }
    {
    }

    ~finally() noexcept {
        if ( _invoke )
            _callable();
    }

private:
    CallableType _callable;
    bool _invoke;
    // ...
```

Allowing move-assignment can similarly be done, but is left as an exercise for the reader.

## Forbidding Null Pointers to Function

In addition to lambdas being callable, plain old pointers to function are also callable and should be allowed without needing a lambda:

```cpp
void clean_up();

int main() {
    finally f{ &clean_up };
    // ...
}
```

But what if that pointer turns out to be null?

```cpp
void (*pf)() = nullptr;
finally f2{ std::move( pf ) };
```

When `f2` goes out of scope, its destructor will call a null pointer to function and likely crash.  What we need is to check to see whether `CallableType` is a pointer to function and, if it is, whether it’s null, and set `_invoke` to `false` in that case.  We can write a helper function:

```cpp
template<std::invocable CallableType>
class finally {
    template<typename T>
    static constexpr bool if_pointer_not_null( T &&p ) {
        using U = std::remove_reference_t<T>;
        if constexpr ( std::is_pointer_v<U> ) {
            return p != nullptr;
        } else {
            (void)p;
            return true;  // not a pointer: can’t be null
        }
    }
public:
    explicit finally( CallableType &&callable ) noexcept :
        _callable{ std::move( callable ) },
        _invoke{ if_pointer_not_null( _callable ) }
    {
    }

    // ...
```

Note that we don’t need to check for pointer-to-function specifically since the `std::invokable` will have already guaranteed that `CallableType` is invokable; so if it’s a pointer, it _must_ be a pointer-to-function. If `CallableType` isn’t a pointer, it’s a lambda, and so can’t be null.

## Take-Aways

When implementing any general utility class like `finally`, think about whether all the special member functions make sense:

+ `T()` — default constructor
+ `T(T const&)` — copy constructor
+ `T(T&&)` — move constructor
+ `T& operator=(T const&)` — copy assignment operator
+ `T& operator=(T&&)` — move assignment operator

For each one, if it makes sense, implement it; if not, `delete` it.  Also try to think of all possible pathological cases (such as a null pointer to function) and handle them.