Witiko Witiko - 3 months ago 28
C++ Question

How does the compiler know which catch block to take?

Suppose I have the following two files,


#include <iostream>

class A {};
void foo();

int main(void)
try {
catch(const A& e) {
std::cout << "Caught an A." << std::endl;
return 0;


class A {};
class B : public A {};

void foo()
B b;
throw b;

Now, when I compile each of these files separately, link the resulting object files, and run the resulting executable, I get the expected result:

$ clang++ --std=c++14 -c main.cpp
$ clang++ --std=c++14 -c foo.cpp
$ clang++ --std=c++14 main.o foo.o
$ ./a.out
Caught an A.

And that boggles my mind! Class
has no virtual methods. Therefore, it is not polymorphic and its instances should carry no type information at runtime. The
object file is unaware of what is being thrown, since the actual throwing takes place inside
, whose body is defined in a separate compilation unit. The
object file has more information, but is equally unaware of any catch statements and the expected types of caught exceptions.

In short: I do not see how the two source files compiled separately and then linked can produce the above input without having some runtime type information at disposal. Neither file compiled separately should have enough information to take the right catch block.


This is of course completely compiler dependent.

The constraints for all the compilers are:

  • the type of the exception is known when you throw (either at compile time, or at runtime in the case you'd throw a polymorphic object).
  • the applicable catch blocks (their can be several) and their types depend on the execution path.

This implies that the type must be recognized at runtime, even if the exception object is non-plymorphic.

An easy way to achieve this is to pass a pointer to a typeinfo object together with the thrown object itself. This is the approach used by GCC: see online code, here an extract of throwing in foo() for convenience:

    call    __cxa_allocate_exception
    mov     edx, 0
    mov     esi, OFFSET FLAT:typeinfo for B   ; <== !! 
    mov     rdi, rax
    call    __cxa_throw