Main Content

MISRA C++:2023 Rule 18.4.1

Exception-unfriendly functions shall be noexcept

Since R2024b

Description

Rule Definition

Exception-unfriendly functions shall be noexcept.

Rationale

These functions are considered exception-unfriendly:

  • Destructors — Destructors can be called during the process of handling an exception that has already occurred. If the destructors themselves exit with an exception, the program terminates. Whether this termination releases the already allocated resources and unwinds the stack is implementation-dependent. Also, destructors of static or global objects can be called after the termination of main(). Any exceptions arising at that point from the destructors remains unhandled, resulting in an abnormal program termination.

  • Copy constructors of exception objects — When throwing an exception, the program copy constructs the exception object. If an exception arises from the copy constructor of the exception object, this exception propagates, which is unexpected behavior. Exception handlers can also copy the exception object. If an exception arises when handlers copy the exception object, the program terminates abnormally.

  • Move constructors and move assignment operators — If the move constructor or move assignment operator of an object is not noexcept, the standard library containers and algorithms can use copy operations instead of move operations. It is difficult to achieve strong exception safety if move operations are not noexcept.

  • Functions named swap — The standard library functions and algorithms expect noexcept implementation of the swap functions. These functions and algorithms can behave abnormally if the swap functions are not noexcept.

  • Functions or constructors that initialize a non-constexpr global variables with static or thread storage duration — These functions are called before the main() function and any exception thrown by these functions cannot be handled, resulting in abnormal termination of the program.

  • Functions and lambdas that are passed as arguments to an extern "C" function — These functions or lambdas are expected to be invoked from C code that cannot handle exceptions.

  • Functions passed as callbacks to std::atexit, std::at_quick_exit, or std::set_terminate as callback functions — An exception in any of these functions results in abnormal termination of the program.

Polyspace Implementation

The rule checker reports a violation of this rule if any of these conditions are true:

  • The copy constructor of a class is not declared noexcept and an object of the class is later thrown as an exception.

  • A class constructor or function that initializes a global variable is not declared noexcept.

  • A move constructor or move assignment operator is not declared noexcept.

  • A function named swap is not declared noexcept.

  • A function or lambda is not declared noexcept and is passed as an argument to an extern "C" function.

  • A noexcept function is passed as a callback function to std::atexit, std::at_quick_exit, or std::set_terminate.

Troubleshooting

If you expect a rule violation but Polyspace® does not report it, see Diagnose Why Coding Standard Violations Do Not Appear as Expected.

Examples

expand all

In this example:

  • The copy constructors of class bad_exception are not declared noexcept. Throwing an object of this class as an exception can result in unexpected behavior. The rule checker reports a violation on the class.

  • The move constructor of the class bad_exception is not declared noexcept. The rule checker reports a violation.

#include <exception>
class bad_exception {  //Noncompliant                         
public:
  bad_exception();                            
  bad_exception(bad_exception&);    
  bad_exception(const bad_exception&); 
  bad_exception(bad_exception&&);   //Noncompliant     
};

class good_exception {
public:
  good_exception() noexcept;                   
  good_exception(good_exception&) noexcept;  
  good_exception(good_exception&&) noexcept; 
};

void foo(){
  throw bad_exception();
  throw good_exception();
}

In this example:

  • The destructor of the class bad_class is not declared noexcept. The rule checker reports a violation.

  • The function init(), which initializes the global variable gV, is not declared noexcept. The rule checker reports a violation.

  • The constructor of the class bad_class initializes the global object global_object but it is not declared noexcept. The rule checker reports a violation.

class bad_class {
	bad_class(int);               // Noncompliant

	~bad_class() noexcept(false);     // Noncompliant
};

bad_class global_object(0);

int init() {
	return 42;    // Noncompliant
}

int gV =init();

Check Information

Group: Exception Handling
Category: Required

Version History

Introduced in R2024b