In C++, I mark a function as noexcept
in the following cases:
The function itself does not throw exceptions, but its value type parameters may throw exceptions when constructing.
The following code demonstrates that situation:
struct A {
A(bool will_throw) {
std::cerr << "Ctor of A\n";
if (will_throw) throw std::runtime_error("An exception from A");
}
A(A&& lhs) noexcept {
std::cerr << "Move ctor of A\n";
}
~A() noexcept = default;
};
struct B {
A mem_;
// Exceptions are thrown during parameter passing, not inside the function
// Thus it isn't an UB I think.
B(A value = A(true)) noexcept : mem_{std::move(value)} {/* do nothing */}
~B() noexcept = default;
};
In this code, the constructor of B
is marked as noexcept
, and the default A(true)
constructor may throw an exception, but I believe this does not lead to undefined behavior since the exception occurs during parameter passing and not within the body of the function.
My question is:
In similar cases, is it safe to mark the constructor and other functions with noexcept
? Can this practice be applied broadly, especially in cases where the function itself does not throw any exceptions?
Trying to propagate an exception out of a noexcept
function doesn't cause UB. It causes std::terminate
to be called.
If you don't want std::terminate
to be called, then it is still safe for a noexcept
function to accept a parameter type whose initialization might throw. See [expr.call]/6
[...] The initialization and destruction of each parameter occurs within the context of the full-expression ([intro.execution]) where the function call appears.
[Example 2: The access ([class.access.general]) of the constructor, conversion functions, or destructor is checked at the point of call. If a constructor or destructor for a function parameter throws an exception, any function-try-block ([except.pre]) of the called function with a handler that can handle the exception is not considered. — end example]