c++ - Can a function be marked noexcept if it takes a value type that may throw? - Stack Overflow

admin2025-04-28  5

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.

The test program is here.

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?

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.

The test program is here.

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?

Share Improve this question edited Jan 9 at 18:13 Konvt asked Jan 9 at 17:54 KonvtKonvt 1257 bronze badges 4
  • 4 Behaviour is well defined. The default parameter is resolved at the call site, before the B constructor is invoked. The exception is thrown. – user4581301 Commented Jan 9 at 18:01
  • 1 Remember that function arguments are passed by value. That means they're all evaluated before the function is called. – Barmar Commented Jan 9 at 18:10
  • 1 Throwing an exception from a noexcept function generally doesn't lead to Undefined Behavior. It only means that std::terminate gets called. – Michael Mahn Commented Jan 9 at 19:14
  • @Michael Mahn — moreover, this exception can be caught in a usual way. noexcept is nothing but a declaration. – Sergey A Kryukov Commented Jan 9 at 22:12
Add a comment  | 

1 Answer 1

Reset to default 4

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]

转载请注明原文地址:http://anycun.com/QandA/1745782611a91225.html