2010-09-22 4 views
6

Предлагает ли C++ способ «показать» что-то визуальное, если возникает необработанное исключение?C++ необработанные исключения

То, что я хочу сделать, это сделать что-то вроде assert(unhandled exception.msg()), если это происходит на самом деле (как в следующем примере):

void foo() { 
    throw std::exception("Message!"); 
} 

int main() { 
foo(); 
} 

Я ожидаю, что этот вид кода не немедленно прекратить (потому что исключение было необработанное), скорее покажите пользовательское сообщение об утверждении (Message! фактически).

Возможно ли это?

+3

Почему бы вам просто не поставить блок try/catch в 'main'? – GManNickG

+1

@GMan: глобальный конструктор или деструктор также может выходить за пределы основного. Для случая деструктора разматывание может не попасть в основной режим. – Potatoswatter

+0

@Potatoswatter: Действительно, я больше интересовался его конкретным примером. – GManNickG

ответ

9

Там нет никакого способа, указанного в стандарте на самом деле отображать сообщение о неперехваченном исключении. Однако на многих платформах это возможно. В Windows вы можете использовать SetUnhandledExceptionFilter и вытащить информацию об исключении C++.С г ++ (соответствующие версии в любом случае), то обработчик прекратить доступ к неперехваченное исключение с кодом, как:

void terminate_handler() 
    { 
     try { throw; } 
     catch(const std::exception& e) { log(e.what()); } 
     catch(...) {} 
    } 

и в самом деле г ++ По умолчанию обработчик прекращает делает что-то похожее на это. Вы можете установить обработчик завершения с помощью set_terminate.

Короче говоря, нет никакого общего способа C++, но есть способы, зависящие от вашей платформы.

+0

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

+0

Кроме того, он может перехватывать исключения, создаваемые глобальными конструкторами и деструкторами, которые невозможно блокировать catch в 'main'. – Potatoswatter

+0

@Potatoswatter Я видел хотя бы одну установку, где этот трюк действительно не работает, я не утверждаю, что достаточно хорошо осведомлен о стандарте (и о других вещах, которые мы делали с обработкой исключений), чтобы сказать один из способов или другой, но я знаю, что он работает на Linux с модернизированным gcc. –

1

Если я правильно прочитал ваш вопрос, вы спрашиваете, можете ли вы перегрузить throw (изменив его поведение по умолчанию), чтобы он сделал что-то определенное пользователем. Нет, ты не можешь.

Edit: так как ты настойчив :), вот плохая идея ™:

#include <iostream> 
#include <stdlib.h> 
#include <windows.h> 

void monkey() { 
    throw std::exception("poop!"); 
} 

LONG WINAPI MyUnhandledExceptionFilter(struct _EXCEPTION_POINTERS *lpTopLevelExceptionFilter) { 
    std::cout << "poop was thrown!" << std::endl; 
    return EXCEPTION_EXECUTE_HANDLER; 
    } 

int main() { 
    SetUnhandledExceptionFilter(&MyUnhandledExceptionFilter); 
    monkey(); 
    return 1; 
} 

Опять же, это очень плохая идея, и это, очевидно, зависит от платформы, но это работает.

+0

Не 'бросить' на самом деле. Я хочу изменить поведение по умолчанию, когда возникает необработанная ситуация с исключениями. –

+0

Так что, когда вы «бросаете» необработанное исключение: -P –

6

Microsoft Visual C++ позволяет подключать необработанные исключения C++ like this. Это standard STL behaviour.

Вы устанавливаете обработчик по вызову set_terminate. Рекомендуется, чтобы ваш обработчик не очень работал, а затем завершал программу, но я не понимаю, почему вы не могли сигнализировать что-либо через assert - хотя у вас нет доступа к исключению, вызвавшему проблему.

+1

Обработчик завершения не должен утверждать. Это может быть 'printf' (или лучше, просто' write (2) 'to' STDERR_FILENO'), и вызвать замененный terminate_handler. Кроме того, см. Ответ Logan и обсуждение того, почему исключение должно быть доступно в этот момент. – Potatoswatter

+0

@Potatoswatter - ваше заявление применимо при любых обстоятельствах - другими словами, можно ли утверждать, но не рекомендуется? Благодарю. –

+0

Всегда можно утверждать, но любой из функций обработчика рекомендуется перехватить ранее установленный обработчик. – Potatoswatter

4

Если вы используете Windows, хорошая библиотека для обработки необработанных исключений и сбоев - CrashRpt. Если вы хотите сделать это вручную, вы также можете use the following I wrote in this answer.

+0

+1 для более широкого ответа на узкий q –

4

Я думаю, что вы выиграли бы от догоняющих всех заявлений следующим образом:

int main() { 
try { 
    foo(); 
catch (...) { 
    // Do something with the unhandled exception. 
} 
} 
+4

Стоит отметить, что само исключение недоступно для интроспекции в этом методе. Это потому, что вы не можете выбрасывать экземпляр 'std :: exception', C++ позволяет вам использовать любой тип значения, например' int' или что-то еще. Вы можете обойти это, также имея 'catch (std :: exception & e)' перед 'catch (...)' или любой тип, который вы, возможно, захотите поймать. – SingleNegationElimination

+0

Действительно. –

+0

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

1

Да, его можно. Здесь вы идете: стандартный

#include <iostream> 
#include <exception> 

void foo() 
{ 
    throw std::exception("Message!"); 
} 

int main() 
{ 
    try 
    { 
    foo(); 
    } 
    catch (std::exception& e) 
    { 
    std::cout << "Got exception: " << e.what() << std::endl; 
    } 

    return 0; 
} 
0

C++ является согласующего обработчик - как и другие сказали

Если вы после лучшего traceablility для броска, то это то, что мы делаем

У нас есть макро Throw который регистрирует имя файла, номер строки и сообщение, а затем выбрасывает. Он принимает сообщение varargs стиля printf.

Throw(proj::FooException, "Fingle %s unable to process bar %d", fingle.c_str(), barNo); 

я получить хорошее журнальное сообщение

Throw FooException from nargle.cpp:42 Fingle barf is unable to process bar 99 
+1

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

+0

, так как он меня бросает (а не время выполнения). Я не в катастрофическом (без памяти, без стека, мертвой кучи) режиме, поэтому обработчик работает. Если нет, тогда я все равно мертв. Я использую эту технику в очень крупных коммерческих продуктах (100s kloc) - без проблем. Я могу настроить уровень ведения журнала, чтобы подавить накладные расходы – pm100

0

Если вы действительно заинтересованы в том, что привело к сбою вашей программы, вам может понадобиться изучить образ процесса в посмертном отладчике. Точный метод немного меняется от ОС к ОС, но основной поезд должен сначала включить сброс ядра, и скомпилировать вашу программу с помощью символов отладки. Как только программа выйдет из строя, операционная система скопирует свою память на диск, и вы сможете проверить состояние программы в момент ее срыва.

Смежные вопросы