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

252
10 октября 2017, 04:55

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

Answer 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<float> v(5);
v.at(5) = 1.0f; // бросит исключение
Answer 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-подобных ошибок

READ ALSO
shared_ptr для динамического массива

shared_ptr для динамического массива

Имеется небольшой класс для создания массива обернутого в shared_ptr, при запуске возникает ошибка : "Невозможно преобразовать int* в int", не могу...

319
Изменение текстового поля на форме из потока QML QT C++

Изменение текстового поля на форме из потока QML QT C++

Пытаюсь изменить значение текстового поля из другого потока, но почему-то не работает( Имеется класс MyThread:

277
проект на mpi Test.exe вызвал срабатывание точки останова

проект на mpi Test.exe вызвал срабатывание точки останова

Простой код с использованием MPIПри сборке в релиз отладка останавливается в указанном месте на ветке else

331
C++ функция Split. Оптимизация

C++ функция Split. Оптимизация

Написал вот такие две функции для нахождения длины строки и разбиение ее на лексемыКак можно еще оптимизировать данный код, не используя...

386