Выявление всех необработанных исключений C++?

Есть ли способ перехватывать исключения, которые в противном случае не обрабатывались (включая те, которые были выброшены вне блока 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);
}
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
27
0
54 280
8
Перейти к ответу Данный вопрос помечен как решенный

Ответы 8

Ответ принят как подходящий

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

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

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

Дело в том, что я действительно не хочу помещать все свое приложение в один большой блок "суперпопробований" ... поскольку производительность критична ... Я знаю, что где-то есть способ, потому что, например, визуальная студия может обнаруживать / ловить / что-то подобное exceptiosn и предлагают взломать и отладить.

Fire Lancer 09.11.2008 19:58

Блок super try работает. Вы оплачиваете стоимость настройки один раз в основном. Один раз - не проблема производительности.

EvilTeach 09.11.2008 20:00

только раз? Я уверен, что однажды внутри блока попытки он поддерживал своего рода «след» для очистки после броска, делая стоимость основанной на содержимом блока?

Fire Lancer 09.11.2008 20:05

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

gbjbaanb 09.11.2008 20:14

Поскольку контекст таков, что он хочет сообщить и прервать выполнение, блок с одной попыткой catch должен сработать для него.

EvilTeach 09.11.2008 21:17

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

Martin York 09.11.2008 23:12

@Fire Lancer: Стоимость взимается только в том случае, если у вас есть исключение. В этот момент ваша скорость выполнения больше не критична, поскольку что-то пошло не так.

Martin York 09.11.2008 23:13

Глобальный catch (...) в основном по-прежнему не будет улавливать исключения в ctors глобальных объектов. Например. Глобальный std :: vector <int> (size_t (-1)) истощит память перед вызовом main ().

MSalters 10.11.2008 17:01

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

EvilTeach 22.01.2009 19:41

@FireLancer: я не знаю, как VS обрабатывает это, но код, выпущенный для gcc, тот же, находится ли он в блоке try или нет, это только путь кода в случае, когда действительно происходит исключение, которое стоит чего-то

PlasmaHH 08.03.2012 18:07

очевидно, что это нужно делать для каждого потока, чтобы захватить all unhandled C++ exceptions, что не всегда легко сделать.

Pavel P 06.06.2018 01:06

catch (...) не поймал необработанные исключения

Jaziri Rami 15.10.2020 18:44

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

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

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

kralyk 22.10.2012 16:38

@kralyk: нет способа перехватить исключения, сгенерированные в конструкторах / деструкторах статических объектов продолжительности хранения. В этом случае вызывается std::terminate().

Martin York 22.10.2012 19:22

Я знаю ... Технически это возможно с помощью set_terminate () (см. Мой ответ), но поскольку статический порядок инициализации определяется реализацией, это тоже не гарантия ...

kralyk 26.10.2012 21:23

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

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

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

В Windows есть файлы .dmp, которые примерно эквивалентны файлам ядра, но они загружаются на веб-сайт отчетов об ошибках Windows (если пользователь нажимает «отправить») вместо того, чтобы засорять жесткий диск пользователя. Кроме того, если у вас настроен своевременный отладчик, Windows вместо этого взломает отладчик.

bk1e 09.11.2008 21:46

конструктор std :: string может вызвать исключение. То же самое и с печатью на std: cerr. С другой стороны, в 99% случаев вам может повезти.

rxantos 07.09.2015 20:37

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

Я знаю, что этот ответ был дан задолго до того, как стал доступен стандарт С ++ 11, но в настоящее время std::set_unexpected устарел.

scrutari 21.06.2016 17:23

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

Проверить std::set_terminate()

Можете ли вы получить доступ к исключению в terminate_handler?

Konstantin A. Magg 02.10.2017 16:41

@ KonstantinA.Magg Я так не думаю. Поскольку исключение может быть типа Любые, на самом деле нет никакого способа получить к нему доступ ...

kralyk 02.10.2017 16:43

Да, вы можете использовать std :: uncaugth_exception () и std :: current_exception {)

Hassen Dhia 30.10.2017 13:57

При условии, что доступен 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

У меня не работает на windows. Вызов std::uncaught_exception возвращает false, даже если прерывание вызвано необработанным throw std::runtime_error("h");.

Diligent Key Presser 24.08.2018 07:18

Другие вопросы по теме