Подтвердить что ты не робот

Как уловить исключение нулевого указателя?

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

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

4b9b3361

Ответ 1

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

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

Ответ 2

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

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

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

Ответ 3

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

Ответ 4

Существует очень простой способ поймать любое исключение (деление на ноль, нарушение прав доступа и т.д.) в Visual Studio с помощью блоков trycatch (...).

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

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

Ответ 5

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

Ответ 6

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

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

Ответ 7

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

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

Ответ 8

Нет такого независимого от платформы способа. В Windows/MSVС++ вы можете использовать __ try/__ except

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

Ответ 9

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

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

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

Ответ 10

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

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

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

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

Ответ 11

В VС++ 2013 (а также более ранних версиях) вы можете поместить контрольные точки на исключения:

  • Нажмите Ctrl + Alt + Delete (это откроет диалог исключения).
  • Разверните 'Исключения Win32'
  • Убедитесь, что исключено исключение "0xC0000005 Access Violation".

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

Ответ 12

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

Ниже приведен пример

.

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;
};

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

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

        cout<<"value="<<e.what()<< endl;
   }