C++ перехватывает все исключения

Есть ли в С ++ эквивалент Java

try {
    ...
}
catch (Throwable t) {
    ...
}

Я пытаюсь отладить код Java / jni, который вызывает собственные функции Windows, и виртуальная машина продолжает давать сбой. Собственный код отлично выглядит при модульном тестировании и дает сбой только при вызове через jni. Общий механизм перехвата исключений оказался бы чрезвычайно полезным.

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

Mooing Duck 08.07.2016 01:16

Что вы можете искать, если оказались здесь: stackoverflow.com/a/32799720/1599699man7.org/linux/man-pages/man2/sigaction.2.htmlman7.org/linux/man-pages/man7/signal.7.html

Andrew 10.11.2020 08:21
Стоит ли изучать 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 называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
269
3
392 760
15

Ответы 15

try {
   // ...
} catch (...) {
   // ...
}

Обратите внимание, что ... внутри catch - это настоящее многоточие, т.е. три точки.

Однако, поскольку исключения C++ не обязательно являются подклассами базового класса Exception, нет никакого способа фактически увидеть переменную исключения, которая создается при использовании этой конструкции.

В C++ 11 есть: try {std :: string (). At (1); // это генерирует std :: out_of_range} catch (...) {eptr = std :: current_exception (); // захватывать }

Mohammad Alaggan 01.01.2013 06:21

@bfontaine: Ну да, но я сказал это, чтобы отличить спецификатор catch от существующего заполнителя кода в комментарии (// ...), который, очевидно, не является синтаксисом C++.

Greg Hewgill 17.01.2014 21:12

@GregHewgill: да, это были типографические придирки.

bfontaine 18.01.2014 01:23

@bfontaine: Достаточно честно. :)

Greg Hewgill 18.01.2014 01:52

Вы можете использовать

catch(...)

но это очень опасно. В своей книге Отладка Windows Джон Роббинс рассказывает военную историю об очень неприятной ошибке, замаскированной с помощью команды catch (...). Намного лучше ловить определенные исключения. Поймайте все, что, по вашему мнению, может вызвать ваш блок try, но позвольте коду генерировать исключение выше, если произойдет что-то действительно неожиданное.

Я просто поймал некоторые из них и приправил некоторые записи на этом этапе. Ничего не делать за исключением исключения - определенно к неприятностям.

jxramos 10.05.2016 00:24
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 25.11.2008 04:18

@coryan, спасибо за напоминание. В последнее время я слишком много времени проводил в мире C#. :)

Greg D 25.11.2008 04:51

@coryan: Почему лучше ловить по константной ссылке?

Tim MB 09.11.2012 21:01

Одно из преимуществ - отказ от ненужных копий.

Greg D 11.11.2012 01:59

-1: предположение, что это «перехватит все исключения в C++», вводит в заблуждение. Попробуйте сгенерировать ошибку деления на ноль внутри блока try. Вы увидите, что это сгенерирует исключение, которое не перехвачено, но код явно написан на C++. Было бы более полезно заявить, что это «перехватит все исключения C++», а затем добавить некоторые упоминания о структурированных исключениях в примечания об ограниченной полезности.

omatai 05.02.2013 05:57

@omatai: исправлено, перехватываются все исключения C++. Деление на ноль является неопределенным поведением и не приводит к возникновению исключения C++.

Mooing Duck 01.03.2013 03:24

@omatai Может показаться вводящим в заблуждение, но все же верно. Деление на ноль вызывает сигнал; он не вызывает исключения. Они разные, и в языке есть терминология для обоих.

Trevor Hickey 14.01.2016 18:09

Но вы можете использовать Windows __try {} __except() для перехвата всех исключений, даже сигналов оборудования, которые обычно приводят к сбою вашего приложения. Проверьте msdn.microsoft.com/en-us/library/s58ftw19.aspx и msdn.microsoft.com/en-us/library/ms681409(v=vs.85).aspx

TheRealChx101 19.02.2016 17:54

Ах, но это был вопрос о C++, а не о расширениях для конкретной платформы.

Greg D 20.02.2016 00:02

Как при использовании синтаксиса ... получить ссылку на пойманную вещь, чтобы я мог распечатать ее, прочитать ее поля или узнать ее тип? Что за тип может быть пойманная вещь, как не std::exception или std::string? Какие другие типы можно использовать в C++?

dinosaur 18.08.2016 00:45

@dinosaur: Ответ покрывает ваш вопрос. Если вы используете более старую разновидность C++, вы не получите ссылки на брошенный объект (который, кстати, может быть любого типа. C++ не ограничивает выбрасываемые типы: isocpp.org/wiki/faq/exceptions#what-to-throw). Если вы используете более новую разновидность C++, вы можете использовать current_exception: cplusplus.com/reference/exception/current_exception.

Greg D 18.08.2016 01:03

@TimMB Еще одним важным преимуществом является то, что он не приводит к нарезке вашего объекта исключения, поэтому виртуальные функции, такие как what(), действительно работают.

Chris Jester-Young 15.12.2016 20:41

@dinosaur причина для вложения блоков catch, как это, состоит в том, чтобы получить работоспособный тип для объекта исключения. C++ требует, чтобы типы переменных были известны во время компиляции, и нет сверхкласса, который можно было бы использовать в качестве родительского типа для каждого исключения; std::exception - самый близкий, но, как видите, не универсальный. Самая большая проблема, с которой я столкнулся, связана с библиотекой Microsoft MFC, которая поддерживала исключения до того, как std::exception был частью языка, поэтому она выдает указатель классу CException.

Mark Ransom 21.03.2019 20:39

Позвольте мне просто упомянуть здесь: Java

try 
{
...
}
catch (Exception e)
{
...
}

НЕ может ловить все исключения! У меня действительно случалось подобное раньше, и это безумно провоцирует; Исключение происходит от Throwable. Итак, буквально, чтобы поймать все, вы НЕ хотите ловить исключения; вы хотите поймать Throwable.

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

Конечно, вы никогда не должны перехватывать объекты Error - если бы вы должны были перехватывать их, они были бы Исключениями. Объекты ошибок - это совершенно фатальные вещи, например, нехватка места в куче и т. д.

SCdF 25.11.2008 05:03

Ни исключений времени выполнения, которые в большинстве случаев являются исключениями GoodProgrammerExpected !!!

OscarRyz 26.11.2008 00:21

У нас была действительно серьезная ошибка, вызванная перехватом OutOfMemoryError из-за блока catch (Throwable) вместо того, чтобы позволить ему убивать вещи ...

Trejkaz 28.06.2012 06:36

Конечно, catch(Exception) может не улавливать все исключения в Java, вы путаете его с C# ... Java = catch(Thowable), C# = catch(Exception). Не запутайте их.

Chef Pharaoh 09.01.2013 18:48

@OscarRyz Это похоже на CoderMalfunctionError (который на самом деле является настоящим подклассом Java Error ... хотя это не означает, как это звучит.)

reirab 04.04.2015 11:01

Возможно, код, перехватывающий Throwable или Error, или один из производных классов от Error, называет это исключением. Но хотя это состояние ошибки, Java явно различает ошибки и исключения. Ваш ответ здесь просто снова сбивает с толку. Если вы выбросите ошибку в своем коде, вы просто вернете ошибку / трассировку стека (если, конечно, вся система не испорчена).

Maarten Bodewes 07.09.2016 18:08

Это не дает ответа на вопрос. Чтобы критиковать или запрашивать разъяснения у автора, оставьте комментарий под его сообщением.

Donald Duck 07.09.2018 14:10

A generic exception catching mechanism would prove extremely useful.

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

Что вам действительно нужно, так это отладчик ...

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

f0ster 13.09.2011 20:57

Я скорее подозреваю, что вы думаете о случаях, когда вы может преследуете какой-то общий образ действий при ошибках, удобно игнорируя те, в которых стек сброшен или память исчерпана, а общая обработка ошибок также не будет успешной. Нет ничего плохого в отлове ошибок, из-за которых вы восстанавливаетесь с помощью может, но ИМХО, все должно существовать только как изолированное (отдельный стек, предварительно выделенная память), тщательно написанная логика, вызываемая непосредственно перед завершением программы; если вы не знаете, в чем проблема, вы не можете быть уверены, что ее можно исправить.

Shog9 13.09.2011 21:22

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

Clearer 26.05.2014 18:19

Кому-то стоит добавить, что в C++ коде нельзя отловить "сбои". Они не создают исключений, но делают все, что им нравится. Когда вы видите, что программа вылетает из-за, скажем, разыменования нулевого указателя, она ведет себя неопределенно. std::null_pointer_exception нет. Попытка поймать исключения здесь не поможет.

На всякий случай кто-то читает эту ветку и думает, что может выяснить причину сбоя программы. Вместо этого следует использовать отладчик, такой как gdb.

Что ж, как указывает Шай, это возможно с компилятором VC. Это плохая идея, но возможно.

Shog9 25.11.2008 04:25

да, с SEH. но не с помощью нормальных стандартных методов C++ :) ну, если вы придерживаетесь окон, вы можете почти все :)

Johannes Schaub - litb 25.11.2008 05:08

Ммм ... спасибо за лакомый кусок. Я искал ответ, почему мои исключения нулевого указателя не улавливаются!

Dalin Seivewright 20.08.2009 15:15

Вы можете отловить segfaults с помощью SEH в Windows и signal (2) / sigaction (2) в системах POSIX, которые охватывают подавляющее большинство систем, используемых сегодня, но, как и обработка исключений, это не то, что следует использовать для нормального управления потоком. Это больше похоже на «сделай что-нибудь полезное перед смертью».

Adam Rosenfield 11.10.2009 20:03

@AdamRosenfield, пока вы не внедрили try { .. } catch(...) { ... } для перехвата с использованием сигнала / sigaction, я бы не назвал это «перехватом» :) Если в обработчике сигнала, программисту относительно сложно узнать, где в коде произошел сбой (я говорить о программном обнаружении этого) по сравнению с try / catch.

Johannes Schaub - litb 23.04.2014 01:01

_set_se_translator можно использовать для перехвата структурированных исключений в Windows как исключений C++. Это включает нарушение доступа для чтения / записи, переполнение стека и деление на ноль.

4LegsDrivenCat 28.12.2019 22:16

в чем разница между catch(...) vs catch(std::exception)?

Mayur 12.11.2020 14:00
  1. Можете ли вы запустить приложение Java с использованием JNI из окна консоли (запустить его из командной строки java), чтобы увидеть, есть ли какой-либо отчет о том, что могло быть обнаружено до того, как JVM разбился. При запуске непосредственно в качестве оконного приложения Java у вас могут отсутствовать сообщения, которые могли бы появиться, если бы вы запускали вместо этого из окна консоли.

  2. Во-вторых, можете ли вы заглушить свою реализацию JNI DLL, чтобы показать, что методы в вашей DLL вводятся из JNI, вы возвращаетесь правильно и т. д.?

  3. На всякий случай, если проблема связана с неправильным использованием одного из методов JNI-интерфейса из кода C++, проверили ли вы, что некоторые простые примеры JNI компилируются и работают с вашей настройкой? Я думаю, в частности, об использовании методов JNI-интерфейса для преобразования параметров в собственные форматы C++ и преобразования результатов функций в типы Java. Полезно заглушить их, чтобы убедиться, что преобразования данных работают, и вы не сбиваетесь с пути в COM-подобных вызовах в интерфейс JNI.

  4. Есть и другие вещи, которые нужно проверить, но трудно предложить что-либо, не зная больше о ваших собственных методах Java и о том, что их реализация JNI пытается сделать. Неясно, связано ли обнаружение исключения на уровне кода C++ с вашей проблемой. (Вы можете использовать интерфейс JNI, чтобы повторно выбросить исключение как Java, но из того, что вы предоставляете, не ясно, что это поможет.)

невозможно (в C++) перехватить все исключения переносимым способом. Это связано с тем, что некоторые исключения не являются исключениями в контексте C++. Сюда входят такие вещи, как деление на ноль ошибок и другие. Можно взломать и, таким образом, получить возможность генерировать исключения при возникновении этих ошибок, но это нелегко сделать и, конечно, нелегко исправить в переносном режиме.

Если вы хотите перехватить все исключения STL, вы можете сделать

try { ... } catch( const std::exception &e) { ... }

Это позволит вам использовать e.what(), который вернет const char*, который может рассказать вам больше о самом исключении. Эта конструкция больше всего напоминает конструкцию Java, о которой вы спрашивали.

Это не поможет вам, если кто-то достаточно глуп, чтобы выбросить исключение, которое не наследуется от std::exception.

почему это не в топе?

Ivan Sanz-Carasa 10.12.2018 13:26

Что касается реальной проблемы невозможности правильно отладить программу, использующую JNI (или ошибка не появляется при ее запуске под отладчиком):

В этом случае часто помогает добавить Java-оболочки вокруг ваших вызовов JNI (т.е. все собственные методы являются частными, а ваши общедоступные методы в классе вызывают их), которые выполняют некоторую базовую проверку работоспособности (убедитесь, что все «объекты» освобождены, а «объекты» не используются после освобождения) или синхронизации (просто синхронизируйте все методы из одной DLL с одним экземпляром объекта). Позвольте методам оболочки java записывать ошибку и генерировать исключение.

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

Если вы знаете причину, сохраните код в методах-оболочках, которые ее избегают. Лучше пусть ваши методы-оболочки генерируют исключения, чем ваш код JNI приводит к сбою виртуальной машины ...

это можно сделать, написав:

try
{
  //.......
}
catch(...) // <<- catch all
{
  //.......
}

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

Надеюсь, вы получили какой-то значок за ответ на вопрос почти через 5 лет после того, как был предоставлен превосходный ответ!

user146043 08.01.2014 21:25

@DrEval Как пожелаете;) stackoverflow.com/help/badges/17/necromancer?userid=2580505

Andreas 04.07.2018 14:16

Короче используйте 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 29.03.2014 11:14

@paykoob Как это справляется со случаями, когда вам удалось создать новый foo, но он потерпел неудачу на панели. Или когда конструктор bar пытается открыть файл, но терпит неудачу и, следовательно, выдает ошибку. тогда вы можете получить опасный фу

Mellester 08.12.2014 21:39

@MelleSterk Разве в этом случае стек не будет очищен, что приведет к запуску деструктора Foo? Я думал, что в этом весь смысл RAII. Однако, если вам нужен указатель на Foo, а не просто создание Foo в стеке, вам нужно обернуть указатель во что-то еще, что объявлено в стеке.

reirab 04.04.2015 11:05

да auto foo = std :: make_unique <Foo> (); автоматическая полоса = std :: make_unique <Bar> (); // безопасен в отношении исключений и не будет протекать, ловушка (...) не требуется

paulm 13.04.2015 09:54

Этот ответ заслуживает голосования хотя бы за начатое им обсуждение :)

Cristik 04.11.2015 23:24

Я из будущего действительно согласен, я из прошлого не понимал RAII в то время

Mellester 16.02.2019 00:23

Вот как вы можете реконструировать тип исключения из 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)?

Mayur 12.11.2020 14:00

В C++ вы можете бросить что угодно, например int. ... тоже это поймает. Вы «должны» ловить исключения const&, кстати.

bobah 12.11.2020 18:26

К вашему сведению, в vs2015 «boost :: current_exception_diagnostic_information ()» просто возвращает «Нет доступной диагностической информации». даже при наличии отладочной информации.

Javanator 18.12.2020 19:05

Что ж, если вы хотите перехватить все исключения, например, для создания минидампа ...

Кто-то проделал работу в 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, не будут обнаружены.

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

MAChitgarha 26.03.2020 18:01

в чем разница между catch(...) vs catch(std::exception)?

Mayur 12.11.2020 14:00

@Mayur catch(...) улавливает исключения уровня языка все, с другой стороны, catch(std::exception) улавливает только исключения типа std::exception, например, если вы вызываете throw 5, только catch(...) поймает это.

muaz 13.11.2020 00:11

Большое спасибо @muaz за разъяснения.

Mayur 13.11.2020 12:42

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