Захват всех необработанных исключений С++?

Есть ли способ поймать исключения, которые в противном случае необработаны (включая те, которые выбрасываются за пределы блока 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);
}

Ответ 1

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

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

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

Ответ 3

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

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

Ответ 4

Без блокировки 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";
   }
}

Ответ 5

Обновление. Это относится только к 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() будет вызываться, если функция генерирует исключение, которое не определено ее спецификацией исключения... что означает, что это работает, только если вы используете спецификации исключений.; (

Ответ 6

Это то, что я всегда делаю в 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! 
    }
}

Ответ 7

При условии, что С++ 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

Ответ 8

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