C ++ - поиск типа перехваченного исключения по умолчанию - PullRequest
11 голосов
/ 03 февраля 2011

Скажи, что у меня есть:

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

Могут быть случаи, когда вы получаете исключение и не знаете, откуда оно и почему - в какой-то внешней библиотеке без отладочной информации. Есть ли способ найти то, что было брошено, или иным образом получить какие-либо данные, связанные с этим? Они могут делать:

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

Но я бы никогда не узнал, поймаю ли я ...

Работа в MSVC ++ 2008, если это имеет значение.

Ответы [ 4 ]

15 голосов
/ 28 июля 2014

Если вы используете gcc или CLANG, вы можете использовать хитрость, чтобы узнать «неизвестный» тип исключения.Имейте в виду, что это нестандартно!

#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);
}
6 голосов
/ 03 февраля 2011

Поскольку C ++ статически типизирован, вы должны поймать известный тип. Однако вы можете вызвать внешнюю функцию (или набор функций), которая обрабатывает типы исключений, неизвестные в точке, где вы их вызываете. Если все эти обработчики имеют известные типы, вы можете зарегистрировать их для динамической проверки.

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.
  }
}

Используйте

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;
    }
  }
}

Цепочка обработчика :

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.
    }
  }
}

Наконец, если вам известны особенности реализации, вы можете использовать их для извлечения любой дополнительной информации, предоставляемой вашей реализацией. C ++ 0x также раскрывает некоторые особенности в переносимой форме; посмотрите на std :: exception_ptr.

2 голосов
/ 03 февраля 2011

Нет способа узнать тип исключения в C ++ (в блоке catch(...), я имею в виду, конечно)

Вы можете просто надеяться, что знаете, что именно externalLibrary::doSomething(); делает, если вы написали это, или, как в вашем случае, вы можете просто надеяться, что есть действительно хорошая документация для externalLibrary::doSomething(); и читать ее, если например. Все хорошие библиотеки имеют подробную документацию.

1 голос
/ 03 февраля 2011

Вы не можете в стандартном C ++.Я бы посчитал такие исключения очень исключительными, и обработал бы их, пытаясь зарегистрировать тот факт, что у вас возникло плохое исключение, а затем попытаться выйти из программы, пока вы все еще можете это сделать., вы можете сохранить любые данные.

...