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?
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.