Есть ли в С ++ эквивалент Java
try {
...
}
catch (Throwable t) {
...
}
Я пытаюсь отладить код Java / jni, который вызывает собственные функции Windows, и виртуальная машина продолжает давать сбой. Собственный код отлично выглядит при модульном тестировании и дает сбой только при вызове через jni. Общий механизм перехвата исключений оказался бы чрезвычайно полезным.
Обратите внимание, что большинство сбоев не вызвано исключениями в C++. Вы можете перехватить все исключения, но это не предотвратит многих сбоев.
Что вы можете искать, если оказались здесь: stackoverflow.com/a/32799720/1599699man7.org/linux/man-pages/man2/sigaction.2.htmlman7.org/linux/man-pages/man7/signal.7.html





try {
// ...
} catch (...) {
// ...
}
Обратите внимание, что ... внутри catch - это настоящее многоточие, т.е. три точки.
Однако, поскольку исключения C++ не обязательно являются подклассами базового класса Exception, нет никакого способа фактически увидеть переменную исключения, которая создается при использовании этой конструкции.
В C++ 11 есть: try {std :: string (). At (1); // это генерирует std :: out_of_range} catch (...) {eptr = std :: current_exception (); // захватывать }
@bfontaine: Ну да, но я сказал это, чтобы отличить спецификатор catch от существующего заполнителя кода в комментарии (// ...), который, очевидно, не является синтаксисом C++.
@GregHewgill: да, это были типографические придирки.
@bfontaine: Достаточно честно. :)
Вы можете использовать
catch(...)
но это очень опасно. В своей книге Отладка Windows Джон Роббинс рассказывает военную историю об очень неприятной ошибке, замаскированной с помощью команды catch (...). Намного лучше ловить определенные исключения. Поймайте все, что, по вашему мнению, может вызвать ваш блок try, но позвольте коду генерировать исключение выше, если произойдет что-то действительно неожиданное.
Я просто поймал некоторые из них и приправил некоторые записи на этом этапе. Ничего не делать за исключением исключения - определенно к неприятностям.
try{
// ...
} catch (...) {
// ...
}
перехватит все исключения C++, но это следует считать плохим дизайном. Вы можете использовать новый механизм C++ 11 current_exception, но если у вас нет возможности использовать C++ 11 (устаревшие кодовые системы, требующие перезаписи), то у вас нет указателя на именованное исключение, которое можно было бы использовать для получения сообщения или имени. . Вы можете добавить отдельные предложения catch для различных исключений, которые вы можете перехватить, и перехватить только все, что находится внизу, для записи неожиданного исключения. Например.:
try{
// ...
} catch (const std::exception& ex) {
// ...
} catch (const std::string& ex) {
// ...
} catch (...) {
// ...
}
Рекомендуется перехватывать исключения по константной ссылке. Как в: catch (std :: exception const & ex) {/ * ... * /}
@coryan, спасибо за напоминание. В последнее время я слишком много времени проводил в мире C#. :)
@coryan: Почему лучше ловить по константной ссылке?
Одно из преимуществ - отказ от ненужных копий.
-1: предположение, что это «перехватит все исключения в C++», вводит в заблуждение. Попробуйте сгенерировать ошибку деления на ноль внутри блока try. Вы увидите, что это сгенерирует исключение, которое не перехвачено, но код явно написан на C++. Было бы более полезно заявить, что это «перехватит все исключения C++», а затем добавить некоторые упоминания о структурированных исключениях в примечания об ограниченной полезности.
@omatai: исправлено, перехватываются все исключения C++. Деление на ноль является неопределенным поведением и не приводит к возникновению исключения C++.
@omatai Может показаться вводящим в заблуждение, но все же верно. Деление на ноль вызывает сигнал; он не вызывает исключения. Они разные, и в языке есть терминология для обоих.
Но вы можете использовать Windows __try {} __except() для перехвата всех исключений, даже сигналов оборудования, которые обычно приводят к сбою вашего приложения. Проверьте msdn.microsoft.com/en-us/library/s58ftw19.aspx и msdn.microsoft.com/en-us/library/ms681409(v=vs.85).aspx
Ах, но это был вопрос о C++, а не о расширениях для конкретной платформы.
Как при использовании синтаксиса ... получить ссылку на пойманную вещь, чтобы я мог распечатать ее, прочитать ее поля или узнать ее тип? Что за тип может быть пойманная вещь, как не std::exception или std::string? Какие другие типы можно использовать в C++?
@dinosaur: Ответ покрывает ваш вопрос. Если вы используете более старую разновидность C++, вы не получите ссылки на брошенный объект (который, кстати, может быть любого типа. C++ не ограничивает выбрасываемые типы: isocpp.org/wiki/faq/exceptions#what-to-throw). Если вы используете более новую разновидность C++, вы можете использовать current_exception: cplusplus.com/reference/exception/current_exception.
@TimMB Еще одним важным преимуществом является то, что он не приводит к нарезке вашего объекта исключения, поэтому виртуальные функции, такие как what(), действительно работают.
@dinosaur причина для вложения блоков catch, как это, состоит в том, чтобы получить работоспособный тип для объекта исключения. C++ требует, чтобы типы переменных были известны во время компиляции, и нет сверхкласса, который можно было бы использовать в качестве родительского типа для каждого исключения; std::exception - самый близкий, но, как видите, не универсальный. Самая большая проблема, с которой я столкнулся, связана с библиотекой Microsoft MFC, которая поддерживала исключения до того, как std::exception был частью языка, поэтому она выдает указатель классу CException.
Позвольте мне просто упомянуть здесь: Java
try
{
...
}
catch (Exception e)
{
...
}
НЕ может ловить все исключения! У меня действительно случалось подобное раньше, и это безумно провоцирует; Исключение происходит от Throwable. Итак, буквально, чтобы поймать все, вы НЕ хотите ловить исключения; вы хотите поймать Throwable.
Я знаю, это звучит придирчиво, но когда вы потратили несколько дней, пытаясь выяснить, откуда взялось "неперехваченное исключение" в коде, который был окружен блоком try ... catch (Exception e) ", он застрял с ты.
Конечно, вы никогда не должны перехватывать объекты Error - если бы вы должны были перехватывать их, они были бы Исключениями. Объекты ошибок - это совершенно фатальные вещи, например, нехватка места в куче и т. д.
Ни исключений времени выполнения, которые в большинстве случаев являются исключениями GoodProgrammerExpected !!!
У нас была действительно серьезная ошибка, вызванная перехватом OutOfMemoryError из-за блока catch (Throwable) вместо того, чтобы позволить ему убивать вещи ...
Конечно, catch(Exception) может не улавливать все исключения в Java, вы путаете его с C# ... Java = catch(Thowable), C# = catch(Exception). Не запутайте их.
@OscarRyz Это похоже на CoderMalfunctionError (который на самом деле является настоящим подклассом Java Error ... хотя это не означает, как это звучит.)
Возможно, код, перехватывающий Throwable или Error, или один из производных классов от Error, называет это исключением. Но хотя это состояние ошибки, Java явно различает ошибки и исключения. Ваш ответ здесь просто снова сбивает с толку. Если вы выбросите ошибку в своем коде, вы просто вернете ошибку / трассировку стека (если, конечно, вся система не испорчена).
Это не дает ответа на вопрос. Чтобы критиковать или запрашивать разъяснения у автора, оставьте комментарий под его сообщением.
A generic exception catching mechanism would prove extremely useful.
Сомнительно. Вы уже знаете, что ваш код сломан, потому что он дает сбой. Использование исключений может замаскировать это, но это, вероятно, приведет к еще более неприятным, более тонким ошибкам.
Что вам действительно нужно, так это отладчик ...
Я не согласен, в приложениях реального времени есть множество случаев, когда я бы предпочел поймать неизвестное исключение, записать что-нибудь в журнал / выполнить какой-то общий курс действий при ошибке, вместо того, чтобы позволить приложению вылететь.
Я скорее подозреваю, что вы думаете о случаях, когда вы может преследуете какой-то общий образ действий при ошибках, удобно игнорируя те, в которых стек сброшен или память исчерпана, а общая обработка ошибок также не будет успешной. Нет ничего плохого в отлове ошибок, из-за которых вы восстанавливаетесь с помощью может, но ИМХО, все должно существовать только как изолированное (отдельный стек, предварительно выделенная память), тщательно написанная логика, вызываемая непосредственно перед завершением программы; если вы не знаете, в чем проблема, вы не можете быть уверены, что ее можно исправить.
Т.е. установите обработчик сигналов, который раскручивает некоторый журнал, созданный вами во время выполнения, чтобы выяснить, где произошел сбой программы и, надеюсь, почему.
Кому-то стоит добавить, что в C++ коде нельзя отловить "сбои". Они не создают исключений, но делают все, что им нравится. Когда вы видите, что программа вылетает из-за, скажем, разыменования нулевого указателя, она ведет себя неопределенно. std::null_pointer_exception нет. Попытка поймать исключения здесь не поможет.
На всякий случай кто-то читает эту ветку и думает, что может выяснить причину сбоя программы. Вместо этого следует использовать отладчик, такой как gdb.
Что ж, как указывает Шай, это возможно с компилятором VC. Это плохая идея, но возможно.
да, с SEH. но не с помощью нормальных стандартных методов C++ :) ну, если вы придерживаетесь окон, вы можете почти все :)
Ммм ... спасибо за лакомый кусок. Я искал ответ, почему мои исключения нулевого указателя не улавливаются!
Вы можете отловить segfaults с помощью SEH в Windows и signal (2) / sigaction (2) в системах POSIX, которые охватывают подавляющее большинство систем, используемых сегодня, но, как и обработка исключений, это не то, что следует использовать для нормального управления потоком. Это больше похоже на «сделай что-нибудь полезное перед смертью».
@AdamRosenfield, пока вы не внедрили try { .. } catch(...) { ... } для перехвата с использованием сигнала / sigaction, я бы не назвал это «перехватом» :) Если в обработчике сигнала, программисту относительно сложно узнать, где в коде произошел сбой (я говорить о программном обнаружении этого) по сравнению с try / catch.
_set_se_translator можно использовать для перехвата структурированных исключений в Windows как исключений C++. Это включает нарушение доступа для чтения / записи, переполнение стека и деление на ноль.
в чем разница между catch(...) vs catch(std::exception)?
Можете ли вы запустить приложение Java с использованием JNI из окна консоли (запустить его из командной строки java), чтобы увидеть, есть ли какой-либо отчет о том, что могло быть обнаружено до того, как JVM разбился. При запуске непосредственно в качестве оконного приложения Java у вас могут отсутствовать сообщения, которые могли бы появиться, если бы вы запускали вместо этого из окна консоли.
Во-вторых, можете ли вы заглушить свою реализацию JNI DLL, чтобы показать, что методы в вашей DLL вводятся из JNI, вы возвращаетесь правильно и т. д.?
На всякий случай, если проблема связана с неправильным использованием одного из методов JNI-интерфейса из кода C++, проверили ли вы, что некоторые простые примеры JNI компилируются и работают с вашей настройкой? Я думаю, в частности, об использовании методов JNI-интерфейса для преобразования параметров в собственные форматы C++ и преобразования результатов функций в типы Java. Полезно заглушить их, чтобы убедиться, что преобразования данных работают, и вы не сбиваетесь с пути в COM-подобных вызовах в интерфейс JNI.
Есть и другие вещи, которые нужно проверить, но трудно предложить что-либо, не зная больше о ваших собственных методах Java и о том, что их реализация JNI пытается сделать. Неясно, связано ли обнаружение исключения на уровне кода C++ с вашей проблемой. (Вы можете использовать интерфейс JNI, чтобы повторно выбросить исключение как Java, но из того, что вы предоставляете, не ясно, что это поможет.)
невозможно (в C++) перехватить все исключения переносимым способом. Это связано с тем, что некоторые исключения не являются исключениями в контексте C++. Сюда входят такие вещи, как деление на ноль ошибок и другие. Можно взломать и, таким образом, получить возможность генерировать исключения при возникновении этих ошибок, но это нелегко сделать и, конечно, нелегко исправить в переносном режиме.
Если вы хотите перехватить все исключения STL, вы можете сделать
try { ... } catch( const std::exception &e) { ... }
Это позволит вам использовать e.what(), который вернет const char*, который может рассказать вам больше о самом исключении. Эта конструкция больше всего напоминает конструкцию Java, о которой вы спрашивали.
Это не поможет вам, если кто-то достаточно глуп, чтобы выбросить исключение, которое не наследуется от std::exception.
почему это не в топе?
Что касается реальной проблемы невозможности правильно отладить программу, использующую JNI (или ошибка не появляется при ее запуске под отладчиком):
В этом случае часто помогает добавить Java-оболочки вокруг ваших вызовов JNI (т.е. все собственные методы являются частными, а ваши общедоступные методы в классе вызывают их), которые выполняют некоторую базовую проверку работоспособности (убедитесь, что все «объекты» освобождены, а «объекты» не используются после освобождения) или синхронизации (просто синхронизируйте все методы из одной DLL с одним экземпляром объекта). Позвольте методам оболочки java записывать ошибку и генерировать исключение.
Это часто помогает найти настоящую ошибку (которая, как ни странно, в основном находится в коде Java, который не подчиняется семантике вызываемых функций, вызывая некоторые неприятные двойные освобождения или что-то подобное) легче, чем попытки отладить массово параллельную программу Java в родной отладчик ...
Если вы знаете причину, сохраните код в методах-оболочках, которые ее избегают. Лучше пусть ваши методы-оболочки генерируют исключения, чем ваш код JNI приводит к сбою виртуальной машины ...
это можно сделать, написав:
try
{
//.......
}
catch(...) // <<- catch all
{
//.......
}
Но здесь есть очень незаметный риск: вы не можете найти точный тип ошибки, которая была выдана в блоке try, поэтому используйте этот тип catch, когда вы уверены, что независимо от типа исключения, программа должен сохраняться способом, определенным в блоке catch.
Надеюсь, вы получили какой-то значок за ответ на вопрос почти через 5 лет после того, как был предоставлен превосходный ответ!
@DrEval Как пожелаете;) stackoverflow.com/help/badges/17/necromancer?userid=2580505
Короче используйте catch(...). Однако обратите внимание, что catch(...) предназначен для использования в основном вместе с throw;:
try{
foo = new Foo;
bar = new Bar;
}
catch(...) // will catch all possible errors thrown.
{
delete foo;
delete bar;
throw; // throw the same error again to be handled somewhere else
}
Это правильный способ использования catch(...).
лучше использовать RAII для управления памятью, которая автоматически обрабатывает эти исключительные ситуации.
@paykoob Как это справляется со случаями, когда вам удалось создать новый foo, но он потерпел неудачу на панели. Или когда конструктор bar пытается открыть файл, но терпит неудачу и, следовательно, выдает ошибку. тогда вы можете получить опасный фу
@MelleSterk Разве в этом случае стек не будет очищен, что приведет к запуску деструктора Foo? Я думал, что в этом весь смысл RAII. Однако, если вам нужен указатель на Foo, а не просто создание Foo в стеке, вам нужно обернуть указатель во что-то еще, что объявлено в стеке.
да auto foo = std :: make_unique <Foo> (); автоматическая полоса = std :: make_unique <Bar> (); // безопасен в отношении исключений и не будет протекать, ловушка (...) не требуется
Этот ответ заслуживает голосования хотя бы за начатое им обсуждение :)
Я из будущего действительно согласен, я из прошлого не понимал RAII в то время
Вот как вы можете реконструировать тип исключения из catch(...), если вам это нужно (может быть полезно при отлове неизвестного из сторонней библиотеки) с помощью GCC:
#include <iostream>
#include <exception>
#include <typeinfo>
#include <stdexcept>
int main()
{
try {
throw ...; // throw something
}
catch(...)
{
std::exception_ptr p = std::current_exception();
std::clog <<(p ? p.__cxa_exception_type()->name() : "null") << std::endl;
}
return 1;
}
и если вы можете позволить себе использовать Способствовать росту, вы можете сделать раздел улова еще проще (снаружи) и потенциально кроссплатформенным.
catch (...)
{
std::clog << boost::current_exception_diagnostic_information() << std::endl;
}
в чем разница между catch(...) vs catch(std::exception)?
В C++ вы можете бросить что угодно, например int. ... тоже это поймает. Вы «должны» ловить исключения const&, кстати.
К вашему сведению, в vs2015 «boost :: current_exception_diagnostic_information ()» просто возвращает «Нет доступной диагностической информации». даже при наличии отладочной информации.
Что ж, если вы хотите перехватить все исключения, например, для создания минидампа ...
Кто-то проделал работу в Windows.
См. http://www.codeproject.com/Articles/207464/Exception-Handling-in-Visual-Cplusplus В статье он объясняет, как он узнал, как перехватывать все виды исключений, и предоставляет работающий код.
Вот список, который вы можете поймать:
SEH exception
terminate
unexpected
pure virtual method call
invalid parameter
new operator fault
SIGABR
SIGFPE
SIGILL
SIGINT
SIGSEGV
SIGTERM
Raised exception
C++ typed exception
И использование: CCrashHandler ch; ch.SetProcessExceptionHandlers (); // делаем это для одного потока ch.SetThreadExceptionHandlers (); // для каждого потока
По умолчанию это создает минидамп в текущем каталоге (crashdump.dmp).
Ну, это действительно зависит от среды компилятора. gcc их не улавливает. Visual Studio и последний Borland, который я использовал, сделали.
Итак, вывод о сбоях заключается в том, что это зависит от качества вашей среды разработки.
C++ Спецификация говорит, что catch (...) должен перехватывать любые исключения, но не во всех случаях.
По крайней мере, из того, что я пробовал.
Быть в курсе
try{
// ...
} catch (...) {
// ...
}
перехватывает только исключения уровня языка, другие исключения / ошибки низкого уровня, такие как Access Violation и Segmentation Fault, не будут обнаружены.
Такие вещи, как ошибка сегментации, на самом деле не являются исключением, это сигналы; таким образом, вы не можете поймать их как типичные исключения. Однако есть некоторые обходные пути, например это.
в чем разница между catch(...) vs catch(std::exception)?
@Mayur catch(...) улавливает исключения уровня языка все, с другой стороны, catch(std::exception) улавливает только исключения типа std::exception, например, если вы вызываете throw 5, только catch(...) поймает это.
Большое спасибо @muaz за разъяснения.
То же, что и Как создать оболочку C++ Dll, которая перехватывает все исключения?