Date: Tue, 1 Sep 2026 11:45:30 +0200
You may have or want a mixture of both models.
- Exceptions you want to annotate and carefully track and be acknowledged (as try catch or as an annotation there) throughout the callstack.
- Exceptions that are not caught or tracked locally, but far up the callstack. For those no annotations should be needed (beyond not using noexcept)
Java did this with checked and unchecked exceptions.
Checked Exceptions signify errors like file errors, user input validation, ..., and are annotated. The program logic is fine, but it is an error condition. It is expected to recover from those.
Unchecked Exceptions are errors in the program logic, division by zero, pre-, post-conditions, invariants; those are not annotated. It is typically *not* expected to recover from those.
-----Ursprüngliche Nachricht-----
Von:Tiago Freire via Std-Proposals <std-proposals_at_[hidden]>
Gesendet:Di 01.09.2026 09:17
Betreff:Re: [std-proposals] fine-control exception/error/UB handling on function boundary
An:std-proposals_at_[hidden];
CC:Tiago Freire <tmiguelf_at_[hidden]>;
I think that makes sense.
If LSP is allowed LSP should apply.
But of course, it depends on what you are trying to achieve with the annotation.
To me what it makes sense to do is to annotate what type of exception you must catch in order to be handled.
If I have
class A;
class B: public A
{
};
void foo() throw(A);
void bar() throw(B);
void woble() noexcept;
decltype(foo) fp1 = bar;
decltype(bar) fp2 = foo; //error
decltype(foo) fp3 = woble;
I.e. if I have void foo() throw(std::runtime_error, std::logic_error);
I only need to catch std::runtime_error, or std::logic_error (or alternative std::exception) to handle all possible exceptions that can possibly be thrown.
And if I do
void woble() noexcept
{
try
{
foo();
} catch(std::runtime_error const& e)
{
//example
}
}
The compiler should warn me I can have uncaught exceptions.
But you can also give the alternative interpretation to enforce exactly the type of exception that is thrown, but I think that would be more cumbersome to use and less useful.
Or even another interpretation Ex.
void foo() throw(std::exception);
void woble() noexcept
{
try
{
foo();
} catch(std::runtime_error const& e) //warning no std::runtime_error is thrown
{
//example
}
}
would not be useful.
-----Original Message-----
From: Std-Proposals <std-proposals-bounces_at_[hidden]> On Behalf Of Simon Schröder via Std-Proposals
Sent: Tuesday, September 1, 2026 07:10
To: std-proposals_at_[hidden]
Cc: Simon Schröder <dr.simon.schroeder_at_[hidden]>; std-proposals_at_[hidden]
Subject: Re: [std-proposals] fine-control exception/error/UB handling on function boundary
> On Sep 1, 2026, at 1:50 AM, Jonathan Grant via Std-Proposals <std-proposals_at_[hidden]> wrote:
>
>
>
> On 28/08/2026 17:33, Tiago Freire via Std-Proposals wrote:
>>> the real problem is as soon as you make that change you have often thousands of functions that cascading need to change because now you changed your interface.
>>
>> Yes, but isn't that just the symptom of a much larger problem.
>> You haven't as much provided a useful function as you have provided a means for your application to ungracefully terminate if you don't document that your code can throw, what it can throw and how you can recover if a function does throw. I.e. you just gave everyone a loaded foot gun.
>>
>> If you state that your function can throw A, B, and C I can write a catch clause to catch A, B, and C and *handle the error*.
>> But now you if you make a change and it can also throw D, the fact that this cascades trough out your entire code base is a good thing.
>> You have changed the contract of what the function can do, code that was previously safe now isn't, and if the caller doesn't catch it you have also changed the caller's contract, then the caller of the caller will throw an additional exception as well.
>>
>> Exceptions are evil because it changes code upstream instead of downstream.
>
> Are these exceptions still derived from std::exception?
> If a sub-system has a failure, and std::exception is caught, it will catch them.
>
> ie subsystem has a new failure mode, but the software was designed for std::out_of_range but std::logic_error is thrown, it would still be caught. Often in these cases it is logged, and the application may, or may not retry the action. It would be better to try and verify at compile-time.
Your comments led me to yet another thought. If we start annotating functions with exceptions, would I have to annotate the exact types of the exceptions or could I use a base type? I would consider it best practice if the exact type is used for the function that throws the exception. But, once the exception travels up the call stack, I might want to write down a base class of the exception instead.
--
Std-Proposals mailing list
Std-Proposals_at_[hidden]
https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
--
Std-Proposals mailing list
Std-Proposals_at_[hidden]
https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
Received on 2026-09-01 09:51:51
