5.2.30 · D5C++ Programming
Question bank — noexcept specifier
Every item is one line: a claim/question, then :::, then the reasoning. The reasoning is the point — never accept a bare "yes/no".
True or false — justify
A noexcept function is guaranteed not to crash.
False —
noexcept only promises no exception escapes; the function can still segfault, deadlock, or infinite-loop. See noexcept specifier: it's a throw-promise, not a safety guarantee.noexcept alone means exactly the same as noexcept(true).
True — writing
noexcept with no parentheses is defined to be shorthand for noexcept(true), the "never throws" promise.An ordinary function with no specifier is treated as noexcept(true).
False — the default for ordinary functions is
noexcept(false) (may throw); only special members like destructors are implicitly noexcept(true).If a noexcept function throws internally but catches it before returning, the contract is broken.
False — only an exception that escapes the function triggers
std::terminate; a try/catch that swallows it fully is perfectly legal.Marking every function noexcept is a free performance win.
False — if such a function can actually throw, you've planted a std::terminate landmine; a false promise turns a recoverable error into an instant crash.
The noexcept(expr) operator actually runs expr to see if it throws.
False —
expr is unevaluated (like sizeof); the operator asks a compile-time question about the declared throwing behaviour, nothing executes.A destructor that throws in C++11 will call std::terminate.
True — destructors are implicitly
noexcept since C++11, so an escaping throw violates the promise and terminates. See Destructors.std::vector always moves elements when it reallocates.
False — it only moves when the element's move constructor is
noexcept; otherwise it copies to preserve the Strong exception guarantee.noexcept(noexcept(x)) contains a typo — you can't nest the keyword.
False — this is intentional: the outer is the specifier, the inner is the operator computing the bool for it. Two roles, one keyword.
A noexcept specifier makes the compiler generate exception-handling tables just in case.
False — the whole payoff is the opposite: the compiler can skip the unwinding machinery here, which is exactly why it must terminate rather than unwind if you lie.
Spot the error
void f() noexcept { throw std::runtime_error("x"); } — what's wrong?
The exception escapes a
noexcept function, so std::terminate fires immediately; a lying promise, not a compile error.std::vector<T> v; speeds up on resize just because T has a move constructor.
The move constructor existing isn't enough — it must be
noexcept, otherwise move_if_noexcept falls back to copying.constexpr bool b = noexcept(risky()); where int risky() { throw 1; } — is b true?
b is false; risky has no noexcept promise (default may-throw), so the operator must assume it could throw. See constexpr.~S() noexcept(false) { throw 1; } "fixes" a throwing destructor.
It compiles and won't call
terminate on its own, but throwing from a destructor during stack unwinding of another exception is still lethal — the real fix is to not throw.A generic swap written noexcept(true) unconditionally is correct.
Wrong — if
T's move can throw, this false promise arms terminate; you need the conditional form noexcept(noexcept(...)).void g() throw(); is the modern way to say "never throws".
throw() is the deprecated/removed C++98 dynamic exception specification; use noexcept instead.Why questions
Why does a broken noexcept promise call terminate instead of just rethrowing?
Because the compiler was allowed to omit the unwinding tables for that function; there may be no info to unwind with, so stopping is the only safe choice.
Why does std::vector copy (not move) elements of a throw-move type on reallocation?
If a move threw halfway, some elements would be in the new buffer and some lost — corrupt state. Copying leaves the originals intact if a copy throws, upholding the Strong exception guarantee.
Why is the noexcept operator's argument left unevaluated?
The question is "could this throw?", answerable from declarations at compile time; running it would defeat the purpose and cause side effects. It mirrors how
sizeof works.Why were destructors made implicitly noexcept in C++11?
A destructor throwing while the stack is already unwinding from another exception is undefined chaos, so the language forbids escape by default. See Move semantics and Destructors.
Why does one keyword ("is your move noexcept?") sometimes double vector resize speed?
It switches the container from copying every element to moving them — moves reuse existing buffers instead of duplicating them, so growth becomes O(pointers) not O(deep copies).
Why can't the compiler just figure out whether a function throws by itself?
Analysis across separate compilation units and virtual/indirect calls is undecidable in general, so the language relies on the programmer's explicit promise instead.
Edge cases
Does noexcept(true) on a function that calls a may-throw helper make the whole thing safe?
No — if that helper's exception escapes, you still hit
terminate; the specifier doesn't magically stop the inner throw, it just changes the punishment.What is noexcept(expr) when expr is something that literally cannot compile (e.g. undeclared)?
It's ill-formed, not
false — the operator needs a well-formed expression; only throwing behaviour is what it evaluates, not validity.Is a function noexcept if every operation inside it is noexcept but it's not marked?
No — without the specifier the function itself is
noexcept(false); being throw-free internally doesn't auto-promote its declared spec.What happens with noexcept(noexcept(T(std::move(a)))) when T's move is deleted?
The inner expression is ill-formed, so the specifier is ill-formed too; the type simply won't satisfy that
swap, rather than quietly becoming may-throw.Can a noexcept function contain a throw statement at all and still be valid code?
Yes — as long as that exception is caught before it escapes; a bare
throw x; with no surrounding catch would leak and terminate at runtime.If move is not noexcept but the type has no copy constructor either, what does vector do on resize?
It is forced to move (there's no copy fallback), so a throwing move can break the strong guarantee for that type — a known trade-off, not a
noexcept violation.Recall One-line self-test
The single sentence that resolves 80% of these traps ::: noexcept is a promise about escape, enforced by terminate, exploited by the compiler to drop unwinding machinery — nothing more, nothing less.