Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.syntblaze.com/llms.txt

Use this file to discover all available pages before exploring further.

The noexcept operator is a compile-time unary operator in C++ that determines whether a given expression is guaranteed to not throw an exception. It evaluates the exception specification of the operations within the expression and yields a boolean prvalue: true if the expression is strictly non-throwing, and false if it is potentially throwing.
noexcept(expression)

Mechanics and Evaluation Context

The expression passed to the noexcept operator is an unevaluated operand. The compiler does not execute the code at runtime; it only performs static analysis on the types and function signatures involved. Because it is evaluated entirely at compile-time, the result of the noexcept operator is a constant expression. The operator returns false if the expression contains any of the following potentially-throwing constructs:
  1. A call to a function, member function, or function pointer that is neither explicitly declared with a non-throwing exception specification (e.g., noexcept or throw()) nor implicitly non-throwing. (Note: Destructors and deallocation functions are implicitly non-throwing by default. Compiler-generated special member functions are conditionally non-throwing; they are implicitly noexcept only if the corresponding special member functions of all base classes and non-static data members are also non-throwing).
  2. A throw expression.
  3. A dynamic_cast expression where the target is a reference type and the conversion requires a run-time check.
  4. A typeid expression applied to a glvalue of a polymorphic class type.
  5. A new expression that invokes an allocation function not declared as non-throwing, or where the initialization of the allocated object (e.g., its constructor) is potentially throwing.
If none of these constructs are present, the operator returns true. Operations on fundamental types (like pointer arithmetic or integer addition) are inherently non-throwing and will evaluate to true.

Operator vs. Specifier

It is critical to distinguish the noexcept operator from the noexcept specifier, although they share the same keyword and are frequently used together.
  • The Operator: Inspects an expression and returns a bool.
  • The Specifier: Attaches an exception specification to a function declaration. It accepts a boolean constant expression to conditionally dictate whether the function can throw.
// 1. noexcept operator (returns a boolean)
constexpr int x = 5;
constexpr int y = 10;
constexpr bool is_safe = noexcept(x + y);

// 2. noexcept specifier (declares function behavior)
void my_function() noexcept; 

// 3. Combined: Specifier taking the result of the operator
template <typename T>
void process(T& obj) noexcept(noexcept(obj.compute())) {
    obj.compute();
}

Syntax Visualization

The following code demonstrates how the compiler evaluates the noexcept operator against various language constructs:
#include <utility>
#include <new>

void throwing_func();
void non_throwing_func() noexcept;

struct A {
    A() {}                      // Potentially throwing (no noexcept specifier)
    ~A() {}                     // Implicitly noexcept (destructors are non-throwing by default)
    void method() noexcept {}   // Explicitly non-throwing
};

struct B {
    A a;                        // Non-static data member with potentially throwing constructor
    // Compiler-generated B() is potentially throwing because A() is potentially throwing
};

// Built-in operations
static_assert(noexcept(1 + 1) == true, "Fundamental math does not throw");

// Function calls
static_assert(noexcept(throwing_func()) == false, "Lacks noexcept specifier");
static_assert(noexcept(non_throwing_func()) == true, "Has noexcept specifier");

// Object construction and destruction
static_assert(noexcept(A()) == false, "Constructor is potentially throwing");
static_assert(noexcept(B()) == false, "Compiler-generated constructor depends on members");
static_assert(noexcept(std::declval<A>().~A()) == true, "Destructor is implicitly non-throwing");

// Member function calls
static_assert(noexcept(std::declval<A>().method()) == true, "Method is noexcept");

// Memory allocation and initialization
static_assert(noexcept(new A) == false, "Standard new can throw std::bad_alloc");
static_assert(noexcept(new (std::nothrow) A) == false, "Allocation is non-throwing, but A's constructor can throw");
Master C++ with Deep Grasping Methodology!Learn More