scaffolding around try{}block #noexcept

[[ARM]] P358 says that all local non-static objects on the current call stack fully constructed since start of the try-block are “registered” for stack unwinding. The registration is fine-grained in terms of partial destruction —

  • for any array with 3 out of 9 objects fully constructed, the stack unwinding would only destruct those 3
  • for a half constructed composite object with sub-objects, all constructed sub-objects will be destructed
  • Any half-constructed object is not registered since the dtor would be unsafe.

I guess this registration is an overhead at run time.

For the stack objects created in a noexcept function, this “registration” is not required, so compiler may or may not call their destructors.

— in Stroustrup hints at the  scaffolding

  • noexcept is a efficiency feature — widely ans systematically used in standard library to improve performance
  • noexcept is crude and “very efficient”
  • dtor may not be invoked upon stack unwinding
  • stack unwinding may not happen at all



noexcept impact on RAII

If a function (esp. dtor) is declared noexcept, compiler can choose to omit stack-unwinding “scaffolding” around it.  Among other things, there’s a runtime performance gain. This gain is a real advantage of using noexcept instead of empty throw() which is deprecated in c++0x.

Q: Is there any impact on RAII?
%%A: yes

Q: Can we even use RAII in such a context?
%%A: I think we can. If the function does throw, then std::terminate() runs, instead of the destructors

Note Best concise intro to noexcept is P780 [[c++primer]]

returning^throwing local object

Tag line – always catch by reference. [[moreEffC++]] has a chapter with this title.

  • If you return a local object by reference, it will lead to run time error as the object would be wiped out from stack. Compiler is likely to give a warning.
  • If you throw a local object and catch by reference up the call stack, it is actually considered best practice, because compiler always clones the local object and throws the clone.

STL: few exceptions #no virtual

side note — virtual function is also very rare in STL classes. I don’t know any.

STL functions seldom throw exception. See P 248 [[c++standard library]]

  1. at() method of vector/string/map… throws, since it’s the “checked” version of the subscript operator
  2. reserve() method throws

Besides these two unusual functions, STL would only throw the standard low-level exceptions like memory allocation failures. All other error conditions are undefined-behavior, such as

  • top()/pop() on priority queue
  • std::string operator[index] with invalid index

However, Payload data types going into STL container can create exceptions:

  • If a payload class ctor/assignment throws, then it would propagate.
  • Payload destructors should never throw. [[c++coding standard]] says it’s forbidden by STL standard.

c++get stacktrace@particular call site #core dump

Not needed in any interview…

It’s easier to trigger core dump in order to get a stack trace. I was successful with raise(SIGABRT)

Here’s a simple demo generating a back trace in a c++ source code. Not sure if it would work in a big code base, but it requires -rdynamic!

#ifdef usage_demo

g++ -g -rdynamic backtrace.cpp # -rdynamic needed
./a.out | perl -pe 's/.*\((.*)\+.*\[(.*)\]/ `c++filt $1` . `addr2line $2` /e;'


#include <execinfo.h>
#include <stdexcept>
using namespace std;
int f2(){
                throw 1;
                void *array[10];
                size_t size = backtrace(array, 10);
                backtrace_symbols_fd(array, size, STDOUT_FILENO);
int f1(){
        return f2();
int main(){

c++q[new] variations

  1. variation: new MyClass(arg1) // most common. Can throw bad_alloc
  2. variation: new MyClass() // better form, calling the no-arg ctor
  3. variation: new MyClass //bare word, same as above. See op-new: allocate^construct #placement #IV
  4. variation: new (nothrow) MyClass(…) // returns NULL upon failure
  5. variation: placement new
  6. variation: array-new // no argument allowed!

reliably convert Any c++ source to C : IV

More than one person asked me “Can you compile a c++ app if you only have a c compiler?”

Some of the foremost experts on c/c++ compiler said on —

If you mean “can you convert C++ source to C source, and run the C through a C compiler to get object code“, as a way to run C++ code on a system that has only a C compiler, yes it is possible to implement all of the features of ISO standard C++ by translation to C source code, and except for exception handling this produces object code with efficiency comparable to that of the code generated by a conventional compiler.

For exception handling, it is possible to do an implementation using setjmp/longjmp that is completely conformant, but the code generated will be 5-20% slower than code generated by a true c++ compiler.

##common c++ run time errors

In java, the undisputed #1 common run time error is NPE, so much so that half of all error checks are null-pointer-checks. In c++, divide-by-zero is similarly a must. But there are more…

– divide by zero
– pointer-move beyond bounds — remember all array sizes are compile-time constants, even with realloc()
– read/write a heap object (heapy thingy) via a reference variable after de-allocation
– return by reference an object allocated on the stack — bulldozed
– dereference (unwrap) a dangling pointer
– c-style cast failure
– double-free
– dereference (unwrap) a null pointer — undefined behavior, unlike java NPE. We should always check null before dereferencing.

—-less common
– delete a pointer to non-heap
– free a pointer to non-heap
– hold pointer/reference to a field of an object, not knowing it’s soon to be reclaimed/bulldozed. Object could be on heap or stack. More likely in multi-threaded programs.
– misusing delete/delete[] on a pointer created with new/new[]. The variable always looks the same — plain pointers.

For any of the above, if it happens in a dtor, you are in double trouble, because the dtor could be executing due to another run time error.

The authoritative [[essential c++]] says that for every exception, there must be a “throw” you can find. Divide-by-zero is something directly done on “hardware” so no chance to throw. I feel many error conditions in C are treated same as in C, without “throw”. In contrast,

  • I feel operator-new is a typical “managed” low level operation that can (therefore does) use exception.
  • dynamic_cast() is anther “managed” low level operation added over C, so it does throw in some cases

Now, JVM “wraps” up all these runtime error Conditions into exceptions. Java creators generally prefer to push these error conditions to the compilation phase, to reduce the variety of Runtime errors. What remain are wrapped up as various RuntimeExceptions. It’s rather remarkable that JVM let’s you catch  all(?) of these exceptions. No undefined behavior.

eg – c++ exception-passing ^ param-passing

Update — [[c++primer]] points out the key concept of ExceptionObject (exo for short) in a try/catch. This is the object thrown, assuming we don’t throw a pointer.

exo isn’t the object created (“object1”) and passed to the “throw” statement. That object1 can have a short lifespan and destroyed much sooner than the exo, which needs a long lifespan — described on P1039. Note exo is copy-constructed from object1. See R1 below.

exo isn’t the object caught either, unless you catch by reference. P1037.

exo IS the object re-thrown if you use the empty throw statement.
Based on [[More effC++]] item on the difference between exception-passing and function-parameter-passing. Illustrates a few rules — R1 R2 R3

class B: public std::exception{};
class C: public B{}; //and so on
class D: public C{}; //and so on
class K: public I{}; //and so on

f(){ D* ex = new K();
  throw *ex; // Copy#1 created [R1] and thrown, sliced [1] to D
  try{ f();}
  catch (exception * ex){} // silently ignored because no “address” is thrown — type mismatch [R2]

  //catch (B ex){} //sliced Copy#2a created, just like function parameter pbclone
  // we will leave the above catch clause commented without further discussion.

  catch(B & exCaught){ //Copy#1 caught without slicing
      //throw; //throws Copy#1 [R3], type D
      throw exCaught; //Copy#2b created [R1] and thrown, sliced[1] to B

[1] slicing by copy-ctor.

empty throw ^ missing throw before c++11

[[Josuttis]] P25 is concise on this topic, and explains why noexcept is superior.

Background – all exception specs beside these 2 are deprecated in c++11. Only these 2 forms proved useful. Let’s rephrase the question as “Real difference between 2 otherwise identical functions, one with empty throw() the other without throw”.

Short Answer — wrapping the empty-throw function call in try/catch is useless.

Short answer – empty throw means “should throw Nothing. Nothing expected“;
Short answer – missing throw means the opposite — “all exceptions expected

Long answer — suppose you wrap each function call in a try/catch (…) ie catch-all. For the function without throw, every single exception from it will fall into your catch(…). For the empty-throw function, every single exception always, always triggers unexpected(). Your try/catch is ignored by compiler — could be removed during compilation.

Now we are ready to look at a function with throw(A). According the ARM, if at runtime this function throws unlisted exceptions, it’s seen as a serious design fault, so serious that compiler will *disregard* your try/catch — paper over (huge) cracks.

Here’s a best practice from — Moral #1: Never write an exception specification. If you follow this advice, then your try/catch will work, ie won’t be stripped off by compiler

My advice — “Either don’t list the exceptions, or adhere to your list. If you bother to list the expected exceptions, then stick to it. Don’t throw anything else. ”

Note unexpected() is called always, always due to an explicit exception-spec i.e. an explicit throw suffix. “Unexpected” means “function author informed compiler to *expect* some exceptions, but something unexpected came out from the function“.

Let’s repeat the message — whenever you notice unexpected() invoked, there’s a function with a broken exception spec — No smoke without fire. No throw suffix then no “unexpected()”.

Further, these 2 conditions always lead to each other —

function has an exception list, but unlisted exceptions generated unexpected() invocation

What about terminate()? It’s somewhat peripheral in the story of exception-spec. I will just describe one of the causes — an expected (i.e. listed) exception is thrown but not caught. Also, unexpected() calls terminate() by default.