Date: Mon, 4 Sep 2023 10:14:45 +0200
Il 04/09/23 08:13, Yexuan Xiao via Std-Proposals ha scritto:
>
>
> Abstract
>
> This paper proposes a new syntax for noexcept-specification,
> noexcept(auto), which deduces the exception specification of a
> function from its body or member initializer list. This feature aims
> to simplify the use of conditional noexcept and avoid the redundancy
> and ugliness of manually writing noexcept expressions.
>
This idea has been raised a few times in the past, cf. N4473, N3202 and
others.
The problems and objections raised by those papers need to be reviewed
and analysed for any new proposal to go forward.
> Motivation
>
> Since C++11 introduced the noexcept specifier, conditional noexcept
> has been widely used in the standard library. It is undeniable that
> noexcept can avoid the compiler generating code to handle exceptions
> and improve performance (both at compile time and run time).
> Therefore, [P2517] and [P2401] added conditional noexcept for some
> simple functions. However, there are still many functions that do not
> use conditional noexcept, but potentially-throwing, such as ranges
> algorithms, std::min, std::greater, etc.
>
> I noticed that Microsoft STL orginally added conditional noexcept
> forstd::greater::operator()
> <https://github.com/microsoft/STL/blob/6c69a73911b33892919ec628c0ea5bbf0caf8a6a/stl/inc/xutility#L409>:
> [snip]
>
(P2401 author here)
MS-STL seems to be a bit more generous than other stdlib implementation
at sprinkling noexcept; when doing research for P2401 it seems that the
presence of a conditional noexcept improves MSVC's debug codegen.
Implementations are anyhow allowed to do so by
[res.on.exception.handling]/5 .
>
> Proposal
>
> I propose to add noexcept(auto) as a placeholder for
> noexcept-specification, which is equivalent to noexcept(false), except
> in the following cases where it is equivalent to noexcept(true):
>
> * It is not a non-throwing function as specified by the standard, and
>
I don't understand what this means.
> * Any function call within the function body or member initializer
> list does not throw exceptions, or
> * The function body is a try block, and the last catch catches all
> exceptions, or
> * Within the function body, any function call that throws an
> exception is wrapped by a try block, and the last catch catches
> all exceptions
>
This is a classification which is way too simple. What if you re-throw
from a catch?
I suspect you really need a long and detailed list, along the lines of
[expr.const], to determine what would make a function noexcept(false).
> Furthermore, in constexpr if and consteval if, the discarded branch
> does not participate in this deduction.
>
>
> Design Decisions
>
> The motivations for this proposal is to simplify the use of
> conditional noexcept in the standard library and user code.
>
As noted before, this simplification has to consider a bunch of things:
1) Is it implementable? Does it require full-program analysis? Does it
risk hitting implementation-defined limits? Do you run into Rice's
theorem? A POC would be very much desirable.
Consider:
void a(int i) noexcept(auto) { if (i > 0) b(i-1); }
void b(int i) noexcept(auto) { if (i > 0) a(i-1); }
What is the compiler supposed to deduce here?
2) Would be acceptable that a "minor" modification of a noexcept(auto)
function does, in fact, change its noexcept-ness, with possibly massive
consequences for callers?
Say you have a move constructor defined as such:
MyClass::MyClass(MyClass &&other) noexcept(auto)
data(std::exchange(other.data), nullptr)
{
countObjectCreated(); // add this for debugging reasons
}
If someone /forgets/ to add noexcept(true) to countObjectCreated(), or
simply /cannot/ add it (it's a C function; it's in another library;
...), then now the whole move constructor is noexcept(false) with
terrible consequences on algorithms and so on.
My 2 c,
>
>
> Abstract
>
> This paper proposes a new syntax for noexcept-specification,
> noexcept(auto), which deduces the exception specification of a
> function from its body or member initializer list. This feature aims
> to simplify the use of conditional noexcept and avoid the redundancy
> and ugliness of manually writing noexcept expressions.
>
This idea has been raised a few times in the past, cf. N4473, N3202 and
others.
The problems and objections raised by those papers need to be reviewed
and analysed for any new proposal to go forward.
> Motivation
>
> Since C++11 introduced the noexcept specifier, conditional noexcept
> has been widely used in the standard library. It is undeniable that
> noexcept can avoid the compiler generating code to handle exceptions
> and improve performance (both at compile time and run time).
> Therefore, [P2517] and [P2401] added conditional noexcept for some
> simple functions. However, there are still many functions that do not
> use conditional noexcept, but potentially-throwing, such as ranges
> algorithms, std::min, std::greater, etc.
>
> I noticed that Microsoft STL orginally added conditional noexcept
> forstd::greater::operator()
> <https://github.com/microsoft/STL/blob/6c69a73911b33892919ec628c0ea5bbf0caf8a6a/stl/inc/xutility#L409>:
> [snip]
>
(P2401 author here)
MS-STL seems to be a bit more generous than other stdlib implementation
at sprinkling noexcept; when doing research for P2401 it seems that the
presence of a conditional noexcept improves MSVC's debug codegen.
Implementations are anyhow allowed to do so by
[res.on.exception.handling]/5 .
>
> Proposal
>
> I propose to add noexcept(auto) as a placeholder for
> noexcept-specification, which is equivalent to noexcept(false), except
> in the following cases where it is equivalent to noexcept(true):
>
> * It is not a non-throwing function as specified by the standard, and
>
I don't understand what this means.
> * Any function call within the function body or member initializer
> list does not throw exceptions, or
> * The function body is a try block, and the last catch catches all
> exceptions, or
> * Within the function body, any function call that throws an
> exception is wrapped by a try block, and the last catch catches
> all exceptions
>
This is a classification which is way too simple. What if you re-throw
from a catch?
I suspect you really need a long and detailed list, along the lines of
[expr.const], to determine what would make a function noexcept(false).
> Furthermore, in constexpr if and consteval if, the discarded branch
> does not participate in this deduction.
>
>
> Design Decisions
>
> The motivations for this proposal is to simplify the use of
> conditional noexcept in the standard library and user code.
>
As noted before, this simplification has to consider a bunch of things:
1) Is it implementable? Does it require full-program analysis? Does it
risk hitting implementation-defined limits? Do you run into Rice's
theorem? A POC would be very much desirable.
Consider:
void a(int i) noexcept(auto) { if (i > 0) b(i-1); }
void b(int i) noexcept(auto) { if (i > 0) a(i-1); }
What is the compiler supposed to deduce here?
2) Would be acceptable that a "minor" modification of a noexcept(auto)
function does, in fact, change its noexcept-ness, with possibly massive
consequences for callers?
Say you have a move constructor defined as such:
MyClass::MyClass(MyClass &&other) noexcept(auto)
data(std::exchange(other.data), nullptr)
{
countObjectCreated(); // add this for debugging reasons
}
If someone /forgets/ to add noexcept(true) to countObjectCreated(), or
simply /cannot/ add it (it's a C function; it's in another library;
...), then now the whole move constructor is noexcept(false) with
terrible consequences on algorithms and so on.
My 2 c,
-- Giuseppe D'Angelo |giuseppe.dangelo_at_[hidden] | Senior Software Engineer KDAB (France) S.A.S., a KDAB Group company Tel. France +33 (0)4 90 84 08 53,http://www.kdab.com
Received on 2023-09-04 08:14:49