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





Это можно использовать для обнаружения неожиданных исключений.
catch (...)
{
std::cout << "OMG! an unexpected exception has been caught" << std::endl;
}
Я не думаю, что без блока try / catch вы можете перехватить исключения, поэтому структурируйте свою программу так, чтобы код показа исключения находился под контролем try / catch.
Блок super try работает. Вы оплачиваете стоимость настройки один раз в основном. Один раз - не проблема производительности.
только раз? Я уверен, что однажды внутри блока попытки он поддерживал своего рода «след» для очистки после броска, делая стоимость основанной на содержимом блока?
производительность не является проблемой, система должна думать о том, что делать, только когда действительно возникает исключение. Раскрутка стека - это то, что приложение должно делать в любом случае, когда объекты выходят за пределы области видимости. Кроме того, попробуйте - так легко поставить try / catch в main, посмотрите, не снизится ли производительность.
Поскольку контекст таков, что он хочет сообщить и прервать выполнение, блок с одной попыткой catch должен сработать для него.
Использование исключения практически не требует затрат в современном компиляторе, если только не возникнет исключение. В этом случае это так же дорого, как и любой другой метод поиска ошибок и сообщения о них.
@Fire Lancer: Стоимость взимается только в том случае, если у вас есть исключение. В этот момент ваша скорость выполнения больше не критична, поскольку что-то пошло не так.
Глобальный catch (...) в основном по-прежнему не будет улавливать исключения в ctors глобальных объектов. Например. Глобальный std :: vector <int> (size_t (-1)) истощит память перед вызовом main ().
@msalters - метод обхода, заключающийся в том, чтобы сделать ваши глобальные указатели и вместо этого разместить их в главном.
@FireLancer: я не знаю, как VS обрабатывает это, но код, выпущенный для gcc, тот же, находится ли он в блоке try или нет, это только путь кода в случае, когда действительно происходит исключение, которое стоит чего-то
очевидно, что это нужно делать для каждого потока, чтобы захватить all unhandled C++ exceptions, что не всегда легко сделать.
catch (...) не поймал необработанные исключения
Это то, что я всегда делаю в 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: нет способа перехватить исключения, сгенерированные в конструкторах / деструкторах статических объектов продолжительности хранения. В этом случае вызывается std::terminate().
Я знаю ... Технически это возможно с помощью set_terminate () (см. Мой ответ), но поскольку статический порядок инициализации определяется реализацией, это тоже не гарантия ...
Вы можете использовать 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 вместо этого взломает отладчик.
конструктор std :: string может вызвать исключение. То же самое и с печатью на std: cerr. С другой стороны, в 99% случаев вам может повезти.
Обновлять: это касается только 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 устарел.
Используйте catch (...) во всех ваших барьерах исключения (а не только в основном потоке). Я предлагаю вам всегда повторно запускать (...) и перенаправлять стандартный вывод / ошибку в файл журнала, так как вы не можете сделать значимый RTTI на (...). OTOH, компилятор, такой как GCC, выдаст довольно подробное описание необработанного исключения: тип, значение what () и т. д.
Проверить std::set_terminate()
Можете ли вы получить доступ к исключению в terminate_handler?
@ KonstantinA.Magg Я так не думаю. Поскольку исключение может быть типа Любые, на самом деле нет никакого способа получить к нему доступ ...
Да, вы можете использовать std :: uncaugth_exception () и std :: current_exception {)
При условии, что доступен 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");.
Дело в том, что я действительно не хочу помещать все свое приложение в один большой блок "суперпопробований" ... поскольку производительность критична ... Я знаю, что где-то есть способ, потому что, например, визуальная студия может обнаруживать / ловить / что-то подобное exceptiosn и предлагают взломать и отладить.