C++ Logo

std-proposals

Advanced search

[std-proposals] Bulldoze Exceptions

From: Frederick Virchanza Gotham <cauldwell.thomas_at_[hidden]>
Date: Sun, 25 Feb 2024 14:03:23 +0000
Let's say you have cleanup code inside a function, something like:

void Func(void *const p, int const arg)
{
    auto cleanup = [p,arg]()
      {
        CleanA();
        CleanB();
        CleanC();
      };

    Auto( cleanup() );

    // Do stuff that hopefully works
}

The cleanup code might throw an exception, and if it does, you want it to
keep bulldozing forward with the cleanup, so you do:

void Func(void *const p, int const arg)
{
    auto cleanup = [p,arg]()
      {
        try { CleanA(); } catch (...){}
        try { CleanB(); } catch (...){}
        try { CleanC(); } catch (...){}
      };

    Auto( cleanup() );

    // Do stuff that hopefully works
}

I was thinking . . . what if we could mark a block of code as 'bulldoze',
meaning that it catches and discards all exceptions. So the lambda becomes:

    auto cleanup = [p,arg]()
      { _Bulldoze:
        CleanA();
        CleanB();
        CleanC();
      };

Of course there would have to be some restrictions inside a block marked as
bulldoze. For example consider:

      { _Bulldoze:
          stringstream ss;
          ss << 77;
          cout << std::move(ss).str();
      }

The problem with this block of code is that if the first line throws, then
we don't have a variable named 'ss' and so the second line is invalid. So
if you define a variable inside a bulldozer block, then there are two rules:

Rule No. 1: The variable must be an intrinsic type, or it must be a class
being constructed with a 'noexcept' constructor.
Rule No. 2: The expressions which are required to be evaluated in order to
construct the variable must all be 'noexcept'.

So the following is valid:

      { _Bulldoze:
          int const i = SomeNoExceptFunc();
          cout << i;
      }

But the following is invalid:

      { _Bulldoze:
          int const i = SomeThrowingFunc();
          cout << i;
      }

If you absolutely must create a variable of class type that might throw,
then use std::optional:

      { _Bulldoze:
          optional<stringstream> ss;
          if ( ss ) *ss << 77;
          if ( ss ) cout << std::move(*ss).str();
      }

Received on 2024-02-25 14:03:25