c++noexceptc++26c++-contracts

Can contract violations result in std::terminate on noexcept functions?


I have some code in the following style:

struct S {
  private:
    T* resource;

  public:
    S(T* r) : resource{r} {
        if (r == nullptr) {
            throw std::invalid_argument(":(");
        }
    }
};

I obviously shouldn't mark this constructor noexcept because it throws an exception. However, what if I write this using C++26 contracts?

S(T* r) noexcept pre(r != nullptr) : resource{r} {}

[basic.contract.handler] doesn't seem to guarantee that the contract violation handler is non-throwing. Therefore, isn't it possible that the contract violation handler throws and std::terminate is called?

I don't really want std::terminate to be called in this situation, so what do I do? Can I make this constructor noexcept? Does noexcept only apply to the function body, not the contracts?


Solution

  • According to [basic.contract.eval]17:

    If a contract-violation handler invoked from the evaluation of a function contract assertion ([dcl.contract.func]) exits via an exception, the behavior is as if the function body exits via that same exception.

    pre defines a "function contract assertion". There's even a note after the above statement that yes, in a noexcept function, a contract-violation handler that emits an exception will invoke std::terminate.

    I don't really want std::terminate to be called in this situation, so what do I do?

    Then you may not want to use contracts for this case. Alternatively, you may want to check with your compiler to ignore them, as a contract violation will otherwise contract-terminate the program. That is, if you want to ensure that the program continues evaluation, contracts are not the tool for the job.