Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ - finding the type of a caught default exception

Say I have:

try
{
 externalLibrary::doSomething();
}
catch (std::exception &e)
{
 //yay I know what to do
}
catch (...)
{
 //darn, I've no idea what happened!
}

There might be cases you get an exception and you don't know where it's coming from or why - in some external library with no debug info. Is there a way to find what was thrown, or otherwise obtain any data associated with it? They might be doing:

throw myStupidCustomString("here is some really useful information");

But I'd never know if I catch ...

Working in MSVC++ 2008 if it matters.

like image 489
Mr. Boy Avatar asked Feb 03 '11 11:02

Mr. Boy


People also ask

How do you catch different types of exceptions?

The try-catch is the simplest method of handling exceptions. Put the code you want to run in the try block, and any Java exceptions that the code throws are caught by one or more catch blocks. This method will catch any type of Java exceptions that get thrown. This is the simplest mechanism for handling exceptions.

What is Rethrowing an exception means in C++?

If a catch block cannot handle the particular exception it has caught, you can rethrow the exception. The rethrow expression ( throw without assignment_expression) causes the originally thrown object to be rethrown.

What are the types of exceptions in C++?

There are two types of exceptions: a)Synchronous, b)Asynchronous (i.e., exceptions which are beyond the program's control, such as disc failure, keyboard interrupts etc.). C++ provides the following specialized keywords for this purpose: try: Represents a block of code that can throw an exception.

How do I get exception messages in C++?

Any code that may throw an exception is placed inside the try block. If an exception is thrown, the catch block is entered, and the program can do the appropriate operation to recover or to alert the user. The code in the finally block is always executed and can do clean up after an exception occurs.


2 Answers

If you use gcc or CLANG you can use a trick to know the 'unknown' exception type. Keep in mind that this is NON-standard !

#include <cstdlib>
#include <iostream>
#include <cxxabi.h>


using namespace __cxxabiv1;

std::string util_demangle(std::string to_demangle)
{
    int status = 0;
    char * buff = __cxxabiv1::__cxa_demangle(to_demangle.c_str(), NULL, NULL, &status);
    std::string demangled = buff;
    std::free(buff);
    return demangled;
}

struct MyCustomClass
{};

int main(int argc, char * argv[])
{
    try
    {
        throw MyCustomClass();
    }
    catch(...)
    {
        std::cout << "\nUnknown exception type: '" << util_demangle(__cxa_current_exception_type()->name()) << "'" << std::endl;
    }
    return(0);
}
like image 97
Grzegorz Wolszczak Avatar answered Oct 07 '22 07:10

Grzegorz Wolszczak


Because C++ is statically typed, you must catch a known type. However, you can call an external function (or set of functions) which handle exception types unknown at the point you call them. If these handlers all have known types, you can register them to be dynamically tried.

struct myStupidCustomString {
  myStupidCustomString(char const *what) : what (what) {}
  char const *what;
};

void throws() {
  throw myStupidCustomString("here is some really useful information");
}

// The external library can provide a function, or you can provide a wrapper, which
// extracts information from "unknown" exception types.
std::string extract_from_unknown_external_exception() {
  try { throw; }
  catch (myStupidCustomString &e) {
    return e.what;
  }
  catch (...) {
    throw;  // Rethrow original exception.
  }
}

Use:

void example() {
  try { throws(); }
  catch (...) {
    try {
      std::string extracted = extract_from_unknown_external_exception();
      std::cout << "extracted: " << extracted << '\n';
    }
    catch (...) {
      // Chain handlers for other types; e.g. exception types from other libraries.
      // Or do something generic for the unknown exception.

      // Or rethrow the original unknown exception:
      throw;
    }
  }
}

Handler chain:

typedef std::string Extract();
std::vector<Extract*> chain (1, &extract_from_unknown_external_exception);
// Chain would normally be initialized using whatever scheme you prefer for
// initializing global objects.
// A list or other container (including a manual linked list that doesn't
// require dynamic allocation) may be more appropriate, depending on how you
// want to register and unregister handlers.
std::string process_chain() {
  for (std::vector<Extract*>::iterator x = chain.begin(); x != chain.end(); ++x) {
    try {
      return (*x)();
    }
    catch (...) {}  // That handler couldn't handle it.  Proceed to next.
  }
  throw;  // None could handle it, rethrow original exception.
}

void example() {
  try { throws(); }
  catch (...) {
    try {
      std::string extracted = process_chain();
      std::cout << "extracted: " << extracted << '\n';
    }
    catch (...) {
      throw;  // Rethrow unknown exception, or otherwise handle it.
    }
  }
}

Finally, if you know implementation specifics, you can use those to extract whatever additional information your implementation exposes. C++0x exposes some specifics in a portable way, too; look at std::exception_ptr.

like image 36
Fred Nurk Avatar answered Oct 07 '22 07:10

Fred Nurk