Поймать все необработанные исключения C ++? - PullRequest
23 голосов
/ 09 ноября 2008

Есть ли какой-нибудь способ перехвата исключений, которые в противном случае не обрабатываются (включая те, которые выбрасываются за пределы блока catch)?

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

что-то вроде:

global_catch()
{
    MessageBox(NULL,L"Fatal Error", L"A fatal error has occured. Sorry for any inconvience", MB_ICONERROR);
    exit(-1);
}
global_catch(Exception *except)
{
    MessageBox(NULL,L"Fatal Error", except->ToString(), MB_ICONERROR);
    exit(-1);
}

Ответы [ 8 ]

25 голосов
/ 09 ноября 2008

Это может быть использовано для обнаружения непредвиденных исключений.

catch (...)
{
    cout << "OMG! an unexpected exception has been caught" << endl;
}

Без блока try catch я не думаю, что вы можете перехватывать исключения, поэтому структурируйте свою программу так, чтобы код обработки исключений находился под контролем try / catch.

19 голосов
/ 08 марта 2012
10 голосов
/ 09 ноября 2008

Вы можете использовать SetUnhandledExceptionFilter в Windows, что будет перехватывать все необработанные исключения SEH.

Как правило, этого будет достаточно для всех ваших проблем, поскольку IIRC все исключения C ++ реализованы как SEH.

8 голосов
/ 09 ноября 2008

Без какого-либо блока catch вы не поймаете никаких исключений. Вы можете иметь блок catch (...) в вашем main () (и его эквивалент в каждом дополнительном потоке). В этом блоке catch вы можете восстановить подробности исключений и сделать что-то с ними, например, войти в систему и выйти.

Однако есть и недостаток в общем блоке catch (...): система обнаружит, что исключение было обработано вами, поэтому оно больше не помогает. В Unix / Linux эта справка будет означать создание файла CORE, который вы можете загрузить в отладчик и увидеть исходное местоположение неисследованного исключения. Если вы обрабатываете его с помощью catch (...), эта информация уже будет потеряна.

В Windows нет файлов CORE, поэтому я бы предложил использовать блок catch (...). Из этого блока вы обычно вызываете функцию для воскрешения фактического исключения:

std::string ResurrectException()
   try {
       throw;
   } catch (const std::exception& e) {
       return e.what();
   } catch (your_custom_exception_type& e) {
       return e.ToString();
   } catch(...) {
       return "Ünknown exception!";
   }
}


int main() {
   try {
       // your code here
   } catch(...) {
       std::string message = ResurrectException();
       std::cerr << "Fatal exception: " << message << "\n";
   }
}
7 голосов
/ 09 ноября 2008

Обновление : распространяется только на c ++ 98.

Из Более эффективного C ++ Мейерса (стр. 76) вы можете определить функцию, которая вызывается, когда функция генерирует исключение, которое не определено в спецификации исключений.

void convertUnexpected()
{
    // You could redefine the exception here into a known exception
    // throw UnexpectedException();

    // ... or I suppose you could log an error and exit.
}

В вашем приложении зарегистрируйте функцию:

std::set_unexpected( convertUnexpected );

Ваша функция convertUnexpected () будет вызываться, если функция генерирует исключение, которое не определено ее спецификацией исключения ... что означает, что это работает, только если вы используете спецификации исключений. ; (

4 голосов
/ 21 июня 2016

При условии, что C ++ 11 доступен, этот подход может быть использован (см. Пример из: http://en.cppreference.com/w/cpp/error/rethrow_exception):

#include <iostream>
#include <exception>

void onterminate() {
  try {
    auto unknown = std::current_exception();
    if (unknown) {
      std::rethrow_exception(unknown);
    } else {
      std::cerr << "normal termination" << std::endl;
    }
  } catch (const std::exception& e) { // for proper `std::` exceptions
    std::cerr << "unexpected exception: " << e.what() << std::endl;
  } catch (...) { // last resort for things like `throw 1;`
    std::cerr << "unknown exception" << std::endl;
  }
}

int main () {
  std::set_terminate(onterminate); // set custom terminate handler
  // code which may throw...
  return 0;
}

Этот подход также позволяет вам настраивать вывод консоли для необработанных исключений: иметь что-то вроде этого

unexpected exception: wrong input parameters
Aborted

вместо этого:

terminate called after throwing an instance of 'std::logic_error'
  what():  wrong input parameters
Aborted
4 голосов
/ 09 ноября 2008

Это то, что я всегда делаю в main ()

int main()
{
    try
    {
        // Do Work
    }
    catch(std::exception const& e)
    {
         Log(e.what());
         // If you are feeling mad (not in main) you could rethrow! 
    }
    catch(...)
    {
         Log("UNKNOWN EXCEPTION");
         // If you are feeling mad (not in main) you could rethrow! 
    }
}
1 голос
/ 10 ноября 2008

Используйте catch (...) во всех ваших исключительных барьерах (не только в главном потоке). Я предлагаю вам всегда перебрасывать (...) и перенаправлять стандартный вывод / ошибку в файл журнала, так как вы не можете сделать значимый RTTI для (...). OTOH, такой компилятор, как GCC, выведет довольно подробное описание необработанного исключения: тип, значение what () и т. Д.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...