#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-подобных
ошибок