Как перехватить исключение нулевого указателя?[дубликат]

StackOverflow https://stackoverflow.com/questions/1823721

Вопрос

На этот вопрос уже есть ответ здесь:

  try {
        int* p = 0;
        *p = 1;
    } catch (...) {
        cout << "null pointer." << endl;
    }

Я пытался поймать исключение, подобное этому, но это не работает, какая-нибудь помощь?

Это было полезно?

Решение

В C ++ нет такого понятия, как "исключение нулевого указателя".Единственные исключения, которые вы можете перехватить, - это исключения, явно генерируемые throw выражения (плюс, как отметил Павел, некоторые стандартные исключения C ++, создаваемые по умолчанию стандартным operator new, dynamic_cast и т.д.).В C ++ нет других исключений.Разыменование нулевых указателей, деление на ноль и т.д.не генерирует исключения в C ++, он создает неопределенное поведение.Если вы хотите, чтобы в подобных случаях возникали исключения, вы сами несете ответственность за ручное обнаружение этих условий и выполнение throw явно.Вот как это работает в C ++.

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

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

Ты не можешь.Отмена ссылки на нулевой указатель - это системная вещь.

В Linux ОС генерирует сигналы в вашем приложении.Взгляните на csignal ( сигнал ) чтобы увидеть, как обрабатывать сигналы.Чтобы "поймать" один из них, вы бы подключили функцию, которая будет вызвана в случае SIGSEGV.Здесь вы могли бы попытаться напечатать некоторую информацию, прежде чем изящно завершить работу программы.

Использование Windows структурированная обработка исключений.Вы могли бы использовать instrumentistics __try/__except, как описано в предыдущей ссылке.То, как я сделал это в определенной утилите отладки, которую я написал, было с помощью функции _set_se_translator (потому что он точно соответствует крючкам).В Visual Studio убедитесь, что у вас включен SEH.С помощью этой функции вы можете подключить функцию для вызова, когда система создает исключение в вашем приложении;в вашем случае это вызвало бы это с EXCEPTION_ACCESS_VIOLATION.Затем вы можете создать исключение и распространить его обратно, как если бы исключение было сгенерировано в первую очередь.

Разыменование null (или указателя, который находится за пределами массива, или случайного недопустимого указателя) приводит к неопределенному поведению.Нет никакого портативного способа "поймать" это.

Существует очень простой способ перехватить любой вид исключения (деление на ноль, нарушение доступа и т.д.) В Визуальная студия используя try -> catch (...) блоки.

Достаточно небольшой настройки проекта.Просто включите /EHa опция в настройках проекта.Видишь Свойства проекта -> C / C ++ -> Генерация кода -> Измените параметр Включить исключения C ++ на "Да с исключениями SEH"..Вот и все!

Смотрите подробности здесь:http://msdn.microsoft.com/en-us/library/1deeycx5 (v=против80).aspx

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

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

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

Как уже говорили другие, вы не можете сделать это на C ++.

Если я могу высказать более широкую точку зрения:даже на языке, который позволяет вам его перехватить, лучшее действие - не трогать нулевые указатели.Улавливать ошибку, когда она уже бросается вам в глаза, а затем принимать решение просто двигаться дальше, как будто этого не произошло, не является хорошей стратегией кодирования.Такие вещи, как разыменование нулевого указателя, переполнение стека и т.д., Следует рассматривать как катастрофические события и всячески избегать, даже если ваш язык позволяет вам реагировать на это по-другому.

Не существует независимого от платформы способа сделать это.В Windows / MSVC ++ вы можете использовать __ попытка/__заисключением

Но я бы все равно не рекомендовал этого делать.Вы почти наверняка не сможете правильно восстановиться после ошибки сегментации.

Если бы вы захотели, вы могли бы просто проверить указатель самостоятельно и выбросить...

if (p == nullptr) throw std::exception("woot! a nullptr!")
p->foo();

так что, конечно, это было бы сделано только для отладки проблемы, nullptr не должен возникать в первую очередь :)

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

Длинный ответ - вы можете сделать больше, чем вы могли бы подумать, и определенно больше, чем просто сбой программы по умолчанию.Однако вам нужно иметь в виду 3 вещи:
1) Эти ошибки БОЛЕЕ серьезны, чем исключения, и часто не могут быть представлены как исключения из вашей логики.
2) Ваше обнаружение и библиотечная обработка их будут зависеть от платформы серверной части, даже если вы можете предоставить чистый абстрактный интерфейс для общего пользования.
3) Всегда будут какие-то сбои, которые настолько серьезны, что вы даже не сможете обнаружить их до конца.

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

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

В VC ++ 2013 (а также более ранних версиях) вы можете устанавливать точки останова для исключений:

  1. Нажмите Ctrl + Alt + Удалить (откроется диалоговое окно исключения).
  2. Разверните раздел "Исключения Win32"
  3. Убедитесь, что установлено исключение "Нарушение доступа 0xC0000005".

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

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

ниже приведен пример для того же самого.

class Exception {

public:
   Exception(const string& msg,int val) : msg_(msg),e(val) {}
  ~Exception( ) {}

   string getMessage( ) const {return(msg_);}
   int what(){ return e;}
private:
   string msg_;
   int e;
};

Теперь, основываясь на проверке нулевого указателя, его можно использовать следующим образом , throw(Exception("NullPointerException",NULL)); и ниже приведен код для перехвата того же самого.

 catch(Exception& e) {
      cout << "Not a valid object: " << e.getMessage( )<< ": ";

        cout<<"value="<<e.what()<< endl;
   }
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top