34

can I get description of an exception caught by

catch(...)

block? something like .what() of std::exception.

MBZ
  • 26,084
  • 47
  • 114
  • 191
  • 1
    In C++11 rethrowing of `std::current_exception` can be used for getting `what` message of exception in catch-all block: http://stackoverflow.com/a/37222762/5447906 – anton_rh May 15 '16 at 04:46

6 Answers6

46

There is one trick you might be able to use:

catch(...) {
    handle_exception();
}

void handle_exception() {
    try {
        throw;
    } catch (const std::exception &e) {
        std::cout << e.what() << "\n";
    } catch (const int i) {
        std::cout << i << "\n";
    } catch (const long l) {
        std::cout << l << "\n";
    } catch (const char *p) {
        std::cout << p << "\n";
    } catch (...) {
        std::cout << "nope, sorry, I really have no clue what that is\n";
    }
}

and so on, for as many different types as you think might be thrown. If you really know nothing about what might be thrown then even that second-to-last one is wrong, because somebody might throw a char* that doesn't point to a nul-terminated string.

It's generally a bad idea to throw anything that isn't a std::exception or derived class. The reason std::exception exists is to allow everybody to throw and catch objects that they can do something useful with. In a toy program where you just want to get out of there and can't even be bothered to include a standard header, OK, maybe throw an int or a string literal. I don't think I'd make that part of a formal interface. Any exceptions you throw are part of your formal interface, even if you somehow forgot to document them.

L. Scott Johnson
  • 4,213
  • 2
  • 17
  • 28
Steve Jessop
  • 273,490
  • 39
  • 460
  • 699
  • 2
    Hi; this is a great answer. I have been looking for some time to find evidence in the standards documents that this is standard behavior, but have been unable to find any. Do you know for certain that this is standard behavior? (That is, entering a new `try`-block inside a `catch(...){}` and rethrowing an exception in order to determine its type.) – NHDaly Nov 13 '13 at 17:10
  • 1
    Working from memory: look for the text about the lifetime of the current exception (until you exit the catch clause), and the effect of a `throw` with no operand (rethrows the current exception). – Steve Jessop Nov 13 '13 at 21:56
5

That block might catch an int, or a const char*, or anything. How can the compiler possibly know how to describe something when it knows nothing about it? If you want to get information off an exception, you must know the type.

Puppy
  • 144,682
  • 38
  • 256
  • 465
  • 5
    "How can the compiler possibly know how to describe something when it knows nothing about it?" - +1, but actually, the compiler does know a little bit about it. The exception mechanism must store *some* type information, because it has to match the exception object against catch clauses. But the standard doesn't define this information or provide access to it, it's a hidden implementation detail. – Steve Jessop Sep 04 '10 at 10:09
  • That type information is nowhere near enough to perform this operation, and no implementation could change that. – Puppy Sep 18 '14 at 08:36
  • 1
    sounds like a challenge ;-) A compiler extension `__what()` that returns a string containing the typeinfo name of the current exception (easy to implement) followed by more characters describing its value (in practice you could easily but rather tediously cover builtin types, and most of the standard library, and maybe have some basic implementations for user-defined types). Of course it would mean the compiler emitting some bloaty code for every type to do its string conversion, but then think how many `operator<<` there are out there already. Doing it for everything, of course not possible. – Steve Jessop Sep 18 '14 at 08:52
4

Since C++11 you can capture the current exception with a pointer:

std::exception_ptr p;     // default initialization is to nullptr

try {
      throw 7;
}
catch(...)
{
     p = std::current_exception();
}

This behaves like a smart pointer; so long as there is at least one pointer pointing to the exception object it is not destroyed.

Later (maybe even in a different function) you can take action in a similar way to the current top answer:

try {
    if ( p )
        std::rethrow_exception(p);
}
catch(int x)
{

}
catch(std::exception &y)
{
}
M.M
  • 138,810
  • 21
  • 208
  • 365
4

If you know you only throw std::exception or subclasses, try

catch(std::exception& e) {...e.what()... }

Otherwise, as DeadMG wrote, since you can throw (almost) everything, you cannot assume anything about what you caught.

Normally catch(...) should only be used as the last defense when using badly written or documented external libraries. So you would use an hierarchy

catch(my::specialException& e) {
      // I know what happened and can handle it
      ... handle special case
      }
catch(my::otherSpecialException& e) {
      // I know what happened and can handle it
      ... handle other special case
      }
catch(std::exception& e) {
      //I can at least do something with it
      logger.out(e.what());
      }
catch(...) {
     // something happened that should not have 
     logger.out("oops");
     }
jdisk
  • 484
  • 3
  • 10
2

How we have our exceptions implemented is that, we have our own Exception classes, that are all derived from std::exception..

Our exceptions will contain Exception message, Function name, File name and line where exceptions are generated. These are all useful not just to show the Messages but also can be used for logging which helps to diagnose the Exception quite easily. So, we get the entire information about the Exceptions generated.

Remember exceptions are for us to get information about what went wrong. So, every bit of information helps in this regard..

liaK
  • 11,422
  • 11
  • 48
  • 73
1

Quoting bobah

#include <iostream>

#include <exception>
#include <typeinfo>
#include <stdexcept>

int main()
{
    try {
        throw ...; // throw something
    }
    catch(...)
    {
        std::exception_ptr p = std::current_exception();
        std::clog <<(p ? p.__cxa_exception_type()->name() : "null") << std::endl;
    }
    return 1;
}
Community
  • 1
  • 1
zangw
  • 43,869
  • 19
  • 177
  • 214
  • 4
    This is not standard or portable. It relies on *implementation-specific details* that differ between compilers. `std::exception_ptr` is a smart shared pointer to an *unspecified* type, so there is no guarantee that `__cxa_exception_type()` exists – Remy Lebeau Nov 30 '17 at 19:03