ATL бросает исключения. В основном это <atlsecurity.h>, также при преобразовании строк при ошибке с локалью. Например, CString::MakeLower бросает. В дебаге там сначала идут ассерты, в релизе — сразу исключения.
Кидает он их хитро:
1. Если требуется, чтобы он кидал пользовательские исключения, можно определить _ATL_CUSTOM_THROW и определить свою AtlThrow(HRESULT hr).
2. Если требуется отказаться от C++ исключений, определить _ATL_NO_EXCEPTIONS и он кидает SEH.
3. Иначе кидает CAtlException.
CAtlException неприятная штука, тем, что это не наследник std::exception, а всего лишь тривиальный враппер для HRESULT. Раузмеется, сам HRESULT в качестве исключения был бы ещё хуже, но даже CAtlException требует своего catch. Поэтому целесообразно определить свой AtlThrow, бросающий наследника std::exception.
Т.к. оригинальный AtlThrow — макро, свой тоже можно определить как макро, дополнительно передав __FILE__ и __LINE__ и получив больше контекста. boost::exception подходит для этой цели, но непосредственно BOOST_THROW_EXCEPTION не подходит, т.к. этот макрос создаёт локальные объекты, требующие раскрутки, а AtlThrow используется в ATL совместно с SEH-обработкой.
Ниже вроде рабочий пример, пробовать в релизе, чтобы сразу был ексепшн, без ассерта.
Здравствуйте, SchweinDeBurg, Вы писали:
SDB>Интересно, только имя не очень удачное ИМХО — будет "сливаться" с _com_error, генерирущимся при использовании директивы #import.
Да, надо как-то так (заодно старые catch(CAtlException) не ломаем):
class CAtlExceptionEx
: public std::exception
, public CAtlException
{
public:
explicit com_error(HRESULT hr) : CAtlException(hr) {}
const char * what( ) const {
...
}
};
Здравствуйте, SchweinDeBurg, Вы писали:
AG>>Кстати, как бы ещё этот _com_error "победить" ?
SDB>В каком смысле? Тоже на потомка std::exception перейти?
Ну да.
Я вообще не использую catch(...), т.к. (1) нельзя ловить некоторые исключения, которые ловятся фреймворками, например boost::thread_interrupted; (2) возможна компиляция с /EHa, но нельзя просто так ловить многие SEH исключения, особенно stack overflow; (3) если где-то бросаются инты, то об этом нужно знать. Соответсвенно, мне хочется, чтобы catch(std::exception&) ловил всё, что имеет смысл ловить.
ИМХО тут даже с макросами будет сложно нашаманить, учитывая что этот код генерит компилятор.
AG>Я вообще не использую catch(...),
Аналогично.
AG>нельзя просто так ловить многие SEH исключения, особенно stack overflow;
Я пользуюсь _set_se_translator(): CSeException (MFC, но сути дела это не меняет — тамошний CException это "аналог" std::exception в том смысле, что является базовым типом для всех исключений).
[ posted via RSDN@Home 1.1.4 stable SR1 r568, accompanied by silence ]
Лучше бы в конце функции установить старый обработчик (который возвращает _set_se_translator), иначе вызывающий может удивиться. Для WinMain это так критично, а например в COM, модуль, содержащий реализацию CSeException::Translator может быть выгружен в самый неподходящий момент.
Можно написать какой-нибудь scoped_translator, который к констукторе вызывает _set_se_translator и запоминает старый обработчик, а в деструкторе — восстанавливает.
Здравствуйте, Юрий Жмеренецкий, Вы писали:
ЮЖ>Можно написать какой-нибудь scoped_translator, который к констукторе вызывает _set_se_translator и запоминает старый обработчик, а в деструкторе — восстанавливает.
Согласен, да и вообще этот пример давно пора поправить — AfxWinMain() там должен быть.
[ posted via RSDN@Home 1.1.4 stable SR1 r568, accompanied by silence ]
Здравствуйте, SchweinDeBurg, Вы писали:
AG>>нельзя просто так ловить многие SEH исключения, особенно stack overflow;
SDB>Я пользуюсь _set_se_translator(): CSeException (MFC, но сути дела это не меняет — тамошний CException это "аналог" std::exception в том смысле, что является базовым типом для всех исключений).
Здравствуйте, Alexander G, Вы писали:
AG>Я вообще не использую catch(...), т.к. (1) нельзя ловить некоторые исключения, которые ловятся фреймворками, например boost::thread_interrupted; (2) возможна компиляция с /EHa, но нельзя просто так ловить многие SEH исключения, особенно stack overflow; (3) если где-то бросаются инты, то об этом нужно знать. Соответсвенно, мне хочется, чтобы catch(std::exception&) ловил всё, что имеет смысл ловить.
Отделить boost::thread_interrupted от, например, CAtlException на общих основаниях навряд ли получится. Однако по крайней мере можно ловить все С++ исключения — это SEH исключения с кодом 0xE06D7363.
Здравствуйте, remark, Вы писали:
R>Отделить boost::thread_interrupted от, например, CAtlException на общих основаниях навряд ли получится.
Поймать CAtlException и не поймать boost::thread_interrupted можно двумя способами: (1) явно поймать CAtlException (2) явно поймать boost::tread_interrupted и сразу же его бросить повторно:
Мне второй способ не особо нравится (хотя про boost::tread_interrupted приходится помнить в любом случае).
R>Однако по крайней мере можно ловить все С++ исключения — это SEH исключения с кодом 0xE06D7363.
Ну да. Казалось бы, пользы немного, их нужно ловить как С++ исключения, чтобы хотя бы деструктор вызвать, однако такому __except есть применение. В некторых случаях я ловлю C++ исключения, вызываю для них MiniDumpWriteDump и бросаю обратно, после чего они штатно обрабатываются. Что-то кроме 0xE06D7363 ловить в тех местах не имеет, т.к. в этом случае приложение всё равно аврийно завершится дамп будет сделан в unhandled exception filter.