Разница между обработкой исключений в C ++ и Java? - PullRequest
23 голосов
/ 20 сентября 2011

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

Однако в C ++, если у меня есть фрагмент кода, который вызываетсбой программы, например:

try
{
    int x = 6;
    int *p = NULL;
    p = reinterpret_cast<int*>(x);

    *p = 10; // the program crashed here

    cout << "x = " << *p << endl;
}
catch(const char* Message)
{
    cout << "There is an run-time error";
}

Затем программа по-прежнему аварийно завершает работу и исключение не перехватывается.

Так в чем же смысл обработки исключений в C ++?Я что-то неправильно понимаю?

Ответы [ 5 ]

31 голосов
/ 20 сентября 2011

Сбой строки - разыменование неверного указателя.В C ++ это не будет исключением.Вместо этого это неопределенное поведение.

В C ++ нет такой вещи, как исключение нулевого указателя, в отличие от Java, которое вызывает исключение нулевого указателя.Вместо этого разыменование недействительного указателя приведет к неопределенному поведению.Неопределенное поведение не всегда подразумевает сбой, однако, если он дает сбой, вам повезло.

Обзор языка:

И наконец, RAII

Одно из самых существенных различий между C ++и Java в том, что Java поддерживает оператор finally.Код в блоке finally всегда выполняется независимо от того, выполняется код в предыдущем блоке catch или нет.Например:

try
{
}
catch (SomeException e)
{
}
finally
{
  //code here is always exectued.
}

Цель оператора finally состоит в том, чтобы разрешить программисту очистку на этом этапе, то есть освобождение сокетов, закрытие файловых дескрипторов и т. Д. Несмотря на то, что Java запускает сборщик мусора, только сборщик мусораотносится к памяти и никаких других ресурсов.Бывают случаи, когда вам нужно вручную утилизировать ресурсы .Теперь в C ++ нет оператора finally, поэтому пользователям языка рекомендуется придерживаться принципа RAII (Resouce Acquisition is Initialization). Страуструп имеет объяснение по этому поводу здесь: http://www.stroustrup.com/bs_faq2.html#finally. Я предпочитаю называть его Resource destruction is deallocation но в основном, когда ваш объект выпадает из области видимости, вызывая деструктор, тогда этот деструктор должен высвобождать любые ресурсы, поддерживаемые объектом.

Например, C ++ 11x предоставляет std :: unique_ptr для управления этим:

void foo()
{
  std::unique_ptr<T> t(new T)
  try
  {
    //code that uses t
  }
  catch (...)
  {
  }
}

Ресурс, выделенный с помощью new, будет удален после завершения функции.

перехват всех операторов

Поскольку все исключения в Java наследуются от общего базового классаException если вы хотите, чтобы ваше предложение catch перехватывало любое исключение, установите его следующим образом:

catch (Exception e)
{
  //any exception thrown will land here.
}

В C ++ нет ограничений на то, что может быть выдано, и нет общего базового класса для всех исключений.Стандартная практика состоит в том, чтобы сформировать свой пользовательский класс исключений путем наследования от std :: exception, но язык не обеспечивает этого.Вместо этого есть специальный синтаксис для перехвата всех исключений:

catch (...)
{

}

Необработанные исключения

Это еще одна область, в которой языки ведут себя по-разному.В C ++ выброшенное исключение, которое не перехватывается, вызывает std :: terminate.Поведение по умолчанию в std :: terminate - это вызов abort, который генерирует SIGABRT, и вся программа останавливается.

В Java поведение состоит в том, чтобы распечатать трассировку стека и завершить поток, в котором возникло необработанное исключение. Однако, посколькуJava-программист может предоставить обработчик UncaughtException, поведение которого вполне может отличаться от используемого по умолчанию завершения потока.

8 голосов
/ 20 сентября 2011

Не все сбои происходят из-за необработанных исключений.В вашем примере стандарт C ++ говорит, что разыменование указателя NULL приводит к неопределенному поведению .В Windows вы можете решать проблемы, которые приводят к аварийному завершению работы вашей программы, не вызывая исключение C ++ с помощью структурированной обработки исключений (SEH): __try / __except / __finally.В Unix вы можете настроить специальные обработчики signal .


Также в вашем коде есть ошибка.Обработчик исключений для const char * будет вызываться только при возникновении исключения этого типа.Для стандартных исключений вы должны поймать std::exception или его соответствующие подклассы.Чтобы перехватить любое исключение C ++, используйте catch (...).

1 голос
/ 20 сентября 2011

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

В Java практически все сообщается с помощью исключения.Все от обычных ожидаемых ошибок («файл не найден» при попытке открыть файл) до критических внутренних ошибок (java.lang.VirtualMachineError).C ++ дает вам выбор: если вы обнаружите ошибку кодирования (ошибка подтверждения), вы можете немедленно прервать процесс (как правило, более подходящий, чем остановка в неизвестном состоянии);если «ошибка» - это то, что обычно происходит в повседневной работе («файл не найден»), вы можете проверить состояние или использовать код возврата (опять же, обычно более подходящий, чем исключение).Для ряда ситуаций между ними (например, нехватка памяти) C ++ использует исключения.

Разумеется, то, что является наиболее подходящим в данном приложении, различается: безусловно, существуют случаи, когда «файл не найден»исключительный (например, если файл является частью приложения, которое не может работать без него) и требует исключения.Аналогично, в определенных случаях нулевой указатель может использоваться для управления логикой программы (if ( ptr == NULL ) ...) или соответствовать исключительному случаю (if ( ptr == NULL ) throw ...);в других случаях нулевой указатель является ошибкой программирования (assert( ptr != NULL)).

1 голос
/ 20 сентября 2011

На самом деле, вы МОЖЕТЕ ловить системные исключения в C ++.Существует опция компилятора (по крайней мере, в Visual Studio), которая позволяет вам отлавливать исключения нарушения прав доступа (именно поэтому ваша программа аварийно завершает работу).

Java более защищена, что создает иллюзию сложности.

Подумайте о следующем:

В Java:

int x[10];
int i = 20;
try
{
    int k = x[i];
}
catch (ArrayIndexOutOfBoundsException ex)
{
     //will enter here
}

Int C ++:

int x[10];
int i = 20;
try
{
    if ( i >= 10 )
        throw new "Index out of bounds";
    int k = x[i];
}
catch (...)
{
    //now it will enter here
}

Все это связано с тем, хотите ли вы оставить больше досреда выполнения (как в случае с Java) или вы сами хотите что-то делать.C ++ дает вам больше контроля, но вы должны уделять больше внимания.

Ваша Java-программа также может аварийно завершить работу, если исключения не будут обработаны - подумайте об этом, если метод явно генерирует исключение, вы не можетене справиться, потому что компилятор не позволяет вам.Если не указано иное, ваша программа все равно будет аварийно завершать работу, если она не окружена try / catch.

Если то, что вы спрашиваете, почему системные исключения не могут быть обработаны в C ++, я уже ответил: они могут, просто по умолчанию это отключено.

0 голосов
/ 04 мая 2017
  1. В C ++ и Java есть блоки try и catch, но в Java наконец-то появился один новый блок, который всегда выполняется после try и catch.
  2. Java выбрасывает только объекты, но C ++ генерирует данные (примитив, указатель и объекты).
  3. C ++ имеет catch (...) {} для перехвата всех исключений всех типов, а Java имеет catch (Exception e) {} для перехвата всех исключений.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...