Warning C26440
Function can be declared 'noexcept'.
C++ Core Guidelines F.6: If your function may not throw, declare it noexcept
If code isn't supposed to cause any exceptions, it should be marked by using the noexcept
specifier. This annotation helps to simplify error handling on the client code side, and enables the compiler to do more optimizations.
Remarks
- A function is considered non-throwing if:
- it has no explicit
throw
statements; - function calls in its body, if any, invoke only functions that are unlikely to throw:
constexpr
or functions marked with any exception specification that entails non-throwing behavior (including some non-standard specifications).
- it has no explicit
- Non-standard and outdated specifiers like
throw()
or__declspec(nothrow)
aren't equivalent tonoexcept
. - Explicit specifiers
noexcept(false)
andnoexcept(true)
are respected appropriately. - Functions marked as
constexpr
aren't supposed to cause exceptions and aren't analyzed. - The rule also applies to lambda expressions.
- The logic doesn't consider recursive calls as potentially non-throwing. This logic may change in the future.
Example
All functions except the destructor will warn because they're missing noexcept.
struct S
{
S() {} // C26455, Default constructor may not throw. Declare it 'noexcept'
~S() {}
S(S&& s) {/*impl*/} // C26439, This kind of function may not throw. Declare it 'noexcept' (f.6)
S& operator=(S&& s) {/*impl*/} // C26439, This kind of function may not throw. Declare it 'noexcept' (f.6)
S(const S& s) {/*impl*/} // C26440, This function can be declared 'noexcept'
S& operator=(const S& s) {/*impl*/} // C26440, This function can be declared 'noexcept'
};
With noexcept decorating the same structure, all warnings are removed.
struct S
{
S() noexcept {}
~S() {}
S(S&& s) noexcept {/*impl*/}
S& operator=(S&& s) noexcept {/*impl*/}
S(const S& s) noexcept {/*impl*/}
S& operator=(const S& s) noexcept {/*impl*/}
};