Страницы

Поиск по вопросам

суббота, 15 февраля 2020 г.

Обработка исключений с++

#cpp #исключения #try_catch


Как обработать исключение, которое возникает при попытке инициализировать значение
за  пределами массива, или при чтении из-за его пределов. Пробовал в catch писать "exception
e", но оно не ловит.
    


Ответы

Ответ 1



если это встроенный c++ массив то можно ставить ассерты перед каждым доступом к его элементу - #define array_size 100 int v[array_size]; int i = 100; assert(i >= 0 && i < array_size); // бросит исключение v[i] = 123; если у вас std::vector то как уже сказали в комментариях - воспользоваться функцией членом std::vector::at которая гарантированно бросит исключение при выходе за пределы вектора. std::vector v(5); v.at(5) = 1.0f; // бросит исключение

Ответ 2



На самом деле в случае выхода за границу массива происходит исключение уровня операционной системы, после чего программе присылается сигнал об этом, и она падает (в комментариях меня поправят, если это не так, но общий смысл такой). Корректная реакция на такие сигналы - завершение программы, поскольку они вызываются недопустимыми операциями и после них программа может не находится в консистентном состоянии. Однако, если очень хочется, то можно такую ошибку отловить и продолжить работу (при этом следует очень хорошо понимать зачем и почему понадобилось так делать, поскольку затея эта целиком и полностью не здоровая). В основе обработки таких ошибок лежат функции setjmp и longjmp, позволяющие сохранить состояние программы и вернутся к сохраненному ранее состоянию. Так же нужно отловить сигнал операционной системы, что делается везде по-своему (Для POSIX-систем достаточно обычных обработчиков сигналов, для windows стоит использовать Structured Exception Handling или Vectored Exception Handling). Итак. Регистрируем обработчик (пример для POSIX). struct sigaction act; memset(&act, 0, sizeof(act)); act.sa_handler = signalHandler; sigaction(SIGSEGV, &act, 0); В обработчике сигнала возвращаемся к сохраненному состоянию и передаем не нулевое значение в качестве возвращаемого для setjmp: jmp_buf env; static void signalHandler(int signum) { longjmp(env, 1); } Перед входом в опасный блок сохраняем состояние программы: try { if (setjmp(env)) throw std::runtime_error("Some shit"); // Действия, которые могут уронить программу Ловим брошенное исключение: } catch (std::runtime_error & e) { // Что-то делаем } Как оно работает. Функция setjmp при сохранении возвращает 0 - исключение не кидается. Если дальше происходит ошибка, то longjmp возвращает выполнение к setjmp, которое в этот момент вернет 1 - бросится исключение, которое можно обработать. Данный пример дает лишь общее представление о логике обработки таких ошибок, для использования его на практике, его стоит доработать. Более полное описание чего куда и зачем можно найти тут: Habrahabr: Обработка многократно возникающих SIGSEGV-подобных ошибок

Комментариев нет:

Отправить комментарий