Как отловить исключение нулевого указателя?
try {
int* p = 0;
*p = 1;
} catch (...) {
cout << "null pointer." << endl;
}
Я пытался поймать исключение, как это, но это не работает, любая помощь?
12 ответов
В C++ нет такого понятия, как "исключение нулевого указателя". Единственные исключения, которые вы можете поймать, это исключения, явно выданные throw
выражений (плюс, как отметил Павел, некоторые стандартные исключения C++ встроены стандартно operator new
, dynamic_cast
так далее). Других исключений в C++ нет. Разыменование нулевых указателей, деление на ноль и т. Д. Не создает исключений в C++, оно вызывает неопределенное поведение. Если вы хотите, чтобы исключения возникали в подобных случаях, вы сами должны вручную определить эти условия и сделать throw
в явном виде. Вот как это работает в C++.
Все, что вы, похоже, ищете, не имеет ничего общего с языком C++, а скорее является особенностью конкретной реализации. Например, в Visual C++ системные / аппаратные исключения можно "преобразовать" в исключения C++, но за эту нестандартную функциональность приходится платить, что обычно не стоит платить.
Ты не можешь. Разыменование нулевого указателя - системная вещь.
В Linux ОС генерирует сигналы в вашем приложении. Взгляните на csignal, чтобы узнать, как обрабатывать сигналы. Чтобы "поймать" один, вы должны подключить функцию, которая будет вызываться в случае SIGSEGV
, Здесь вы можете попытаться распечатать некоторую информацию, прежде чем завершить программу.
Windows использует структурированную обработку исключений. Вы могли бы использовать Instristics __try/__except
, как указано в предыдущей ссылке. То, как я сделал это в определенной утилите отладки, которую я написал, было с помощью функции _set_se_translator
(потому что это близко соответствует крюкам). В Visual Studio убедитесь, что у вас включен SEH. С помощью этой функции вы можете подключить функцию для вызова, когда система вызывает исключение в вашем приложении; в вашем случае это называется EXCEPTION_ACCESS_VIOLATION
, Затем вы можете выбросить исключение и заставить его распространяться обратно, как если бы исключение было выброшено в первую очередь.
Существует очень простой способ отловить любое исключение (деление на ноль, нарушение доступа и т. Д.) В Visual Studio с помощью try
-> catch (...)
блоки.
Незначительная настройка проекта достаточно. Просто включите /EHa
опция в настройках проекта. См. Свойства проекта -> C/C++ -> Генерация кода -> Измените параметр Включить исключения C++ на "Да с исключениями SEH". Это оно!
Подробности смотрите здесь: http://msdn.microsoft.com/en-us/library/1deeycx5%28v=vs.80%29.aspx
Разыменование нулевого значения (или указателя, находящегося за концом массива, или случайного неверного указателя) приводит к неопределенному поведению. Нет портативного способа "поймать" это.
C++ не выполняет проверку указателя (хотя я полагаю, что некоторые реализации могут). Если вы попытаетесь записать нулевой указатель, скорее всего, произойдет сбой. Это не бросит исключение. Если вы хотите поймать это, вам нужно проверить значение указателя самостоятельно, прежде чем пытаться записать его.
Как правило, вы не можете. Даже если бы вы могли, это было бы все равно, что пытаться надеть лейкопластырь на подводную лодку, в которой произошла утечка.
Искаженное приложение может нанести гораздо больший ущерб, чем поврежденное. Мой совет здесь должен был позволить этому разбиться тогда, чтобы установить, почему это упало. Полоскание. Повторение.
Как уже говорили другие, вы не можете сделать это в C++.
Если я могу сделать более широкое замечание: даже на языке, который позволяет вам его уловить, лучше не трогать нулевые указатели. Поймать ошибку, когда она уже взорвана на вашем лице, а затем принять решение просто двигаться дальше, как будто это не произошло, не является хорошей стратегией кодирования. Такие вещи, как разыменование нулевого указателя, переполнение стека и т. Д., Следует рассматривать как катастрофические события, которых следует избегать, даже если ваш язык позволяет реагировать на них по-разному.
Не существует независимого от платформы способа сделать это. Под Windows/MSVC++ вы можете использовать __try/ __ кроме
Но я бы не советовал делать это в любом случае. Вы почти наверняка не сможете правильно восстановиться после ошибки сегментации.
В VC++ 2013 (а также в более ранних версиях) вы можете устанавливать точки останова для исключений:
- Нажмите Ctrl + Alt + Delete (откроется диалоговое окно исключения).
- Разверните "Исключения Win32"
- Убедитесь, что исключение "0xC0000005 Access Violation" проверено.
Теперь снова выполните отладку, точка останова будет достигнута именно тогда, когда произошла нулевая разыменование.
Короткий ответ - вы не можете это сделать портативным или стандартным способом, потому что подобные ошибки потенциально могут повредить сам процесс.
Длинный ответ - вы можете сделать больше, чем вы думаете, и, безусловно, больше, чем просто по умолчанию программы просто сбой. Тем не менее, вам нужно помнить 3 вещи:
1) Эти ошибки более серьезны, чем исключения, и часто не могут быть представлены как исключения из вашей логики.
2) Ваше обнаружение и обработка их библиотек будет зависеть от платформы на стороне сервера, даже если вы можете предоставить чистый абстрактный интерфейс для общего пользования.
3) Всегда будут некоторые сбои, которые настолько плохи, что вы даже не сможете обнаружить их до конца.
По сути, ошибки, такие как ошибки сегмента или повреждение кучи, не являются исключениями, поскольку они повреждают реальный процесс, выполняющий программу. Все, что вы закодировали в программе, является частью программы, включая обработку исключений, поэтому все, что не записывается в виде красивого сообщения об ошибке до того, как процесс умирает, нецелесообразно в тех случаях, когда это невозможно. В POSIX ОС использует систему сигнализации для сообщения об ошибках, подобных этим, и вы можете зарегистрировать функции обратного вызова, чтобы записать, что за ошибка была перед выходом. В Windows ОС иногда может преобразовывать их в нормально выглядящие исключения, которые вы можете перехватить и восстановить.
В конечном счете, однако, вам лучше всего защищаться от таких кошмаров. В любой операционной системе будут такие плохие программы, что вы не сможете обнаружить их, даже в принципе, до того, как ваш процесс умрет. Например, повреждение вашего собственного указателя стека может настолько сильно вас сломать, что даже ваши обратные вызовы сигнала POSIX никогда его не увидят.
Если вы хотите, вы можете просто проверить указатель и бросить...
if (p == nullptr) throw std::exception("woot! a nullptr!")
p->foo();
таким образом, конечно, это будет только для устранения проблемы, nullptr не должен возникать в первую очередь:)
В C++ не существует исключения 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;
}