Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Для новичков > Как перехватить исключение


Автор: neosapient 10.10.2014, 14:57
Здравствуйте.

Настроил проект на перехват исключений в настройках проекта:
  С\С++ -> Code Generation
  Enable C++ Exeption = Yes With SEH Exceptions (/EHa)

Тестирую обычное деление на 0 - исключение перехватывается.

Делаю более сложный тест: обращаюсь к -1 (минус первой) ячейке вектора
Код

#include <iostream>
#include <vector>

int main() {
    try{
        std::vector<int> arr;
        int val = arr[-1];
        std::cout << "successful";
    return 0;
    }catch(...)
    {
        std::cout << "exeption";
    }
}

И программа падает, а исключение перехватить не получается ((

P.S.
Прикрепил пример с программой к посту. (test_exeption.zip)
Использую Visual Studio 2008

P.P.S.
Для тех кто любит веб IDE, http://ideone.com/YaVxGX
Но исключений в этой веб IDE не возникает, так что для демонстраций она бесполезна

Автор: sQu1rr 10.10.2014, 15:03
Ну так а кто сказал что исключение должно бросаться
http://www.cplusplus.com/reference/vector/vector/operator%5B%5D/
бросается тут: std::vector::at()
http://www.cplusplus.com/reference/vector/vector/at/

Автор: neosapient 10.10.2014, 15:13
Хм, а что тогда происходит?
Там же (в глубинах std-библиотеки) нет exit(-1); ?

Программа вылетает - надо это как то перехватить.
Какие есть варианты?

Автор: sQu1rr 10.10.2014, 15:17
Цитата

The definition of the subscript operator [] is that E1[E2] is identical to (*((E1)+(E2))).

то есть arr[-1] - вполне валидно, и вы сами должны проверять плохо это или хорошо. ваша программа вылетает, потому что visual studio шаманит с памятью, наделе же это UB

Автор: neosapient 10.10.2014, 15:36
Может есть какие-либо флаги в настройке проекта, чтобы visual studio не шаманила с памятью?
Что значит аббревиатура UB?

Автор: sQu1rr 10.10.2014, 15:50
Цитата(neosapient @  10.10.2014,  15:36 Найти цитируемый пост)
Что значит аббревиатура UB?

http://lmgtfy.com/?q=UB+C%2B%2B

Цитата(neosapient @  10.10.2014,  15:36 Найти цитируемый пост)
Может есть какие-либо флаги в настройке проекта, чтобы visual studio не шаманила с памятью?

А может и не шаманит, я тончо не помню, может кто тут точно скажет. В любом случае, зачем вам это? почему бы просто не пользоваться at()? или сделать свой вектор в блекджеком и переопределенном операторе [] который вызывает at()

Автор: DarthTon 10.10.2014, 16:05
Цитата

И программа падает, а исключение перехватить не получается ((

Вы точно в релиз билде запускаете? А то в дебажном оно просто покажет assertion failed; это перехватывать не стоит. В релизном будет Access violation по адресу 0xFFFFFFFC(т.к. пустой вестор по-умолчанию инициализирует начальный указатель в 0) которое нормально ловится catch(...).
UD - undefined behavior. В общем случае поведение не определено, ибо arr[-1] фактически вернёт значение в ячейке которая находится перед ячейкой 0-го елемента вектора. А состояние той ячейки может быть каким-угодно.

В веб ИДЕ исключение не возникает потому что там оптимизирована строка "int val = arr[-1];" и она не исполняется на самом деле.

Автор: neosapient 10.10.2014, 16:32
DarthTon,
Ни в дебаге, ни в релизе исключение в catch не ловится 

Автор: sQu1rr 10.10.2014, 16:37
Цитата(DarthTon @  10.10.2014,  16:05 Найти цитируемый пост)
которое нормально ловится catch(...)

С чего бы это?

Цитата(neosapient @  10.10.2014,  16:32 Найти цитируемый пост)
Ни в дебаге, ни в релизе исключение в catch не ловится  

Потому что С++ не генерирует исключения такие вещи. вы объясните что вы хотите реализовать

Автор: korian 10.10.2014, 16:48
Цитата(neosapient @  10.10.2014,  14:13 Найти цитируемый пост)
Программа вылетает - надо это как то перехватить.
Какие есть варианты? 

я думаю в релизе не должна вылетать.
покрайней мере не на этой строчке. Потому шо это с точки зрения языка вполне нормальная законная операция, которая не подразумевает никаких ошибок. И врядли оно выделит память там, где в [-1] нельзя писать.
а segfault наверно в эксепшены не оборачивается, бо нормально восстановиться после такого нереально

Автор: DarthTon 10.10.2014, 17:12
Цитата

С чего бы это?

Ибо /Eha и Access violation. В этом случае crt функция FindHandlerForForeignException пытается найти catch(...) хендлер в списке SEH фреймов, и если находит, в этот хендлер передаётся Win32 исключение преобразованное к С++ исключению.
А вообще, что происходит при выполнение программы? Она падает? Где падает, с каким исключением?

Автор: Lukkoye 10.10.2014, 18:26
Вы хотите что то типа такого?

http://rextester.com/LGS53967

Код

#include <iostream>
#include <signal.h>
#include <vector>


void reaction_for_crash(const int signalnum);
void fnExit() {  puts ("User`s procedure of terminate process"); }

 void intercept_crash_state()
 {
    atexit(fnExit); 
    signal(SIGABRT, reaction_for_crash); 
    signal(SIGSEGV, reaction_for_crash);
    signal(SIGILL , reaction_for_crash);
    signal(SIGFPE , reaction_for_crash);
      
    #ifndef _MSC_VER
         signal(SIGBUS,  handle); 
    #endif
 }

int main()
{
    std::cout << "Hello, world!\n";
    
    intercept_crash_state();
    std::vector<int> arr;
    int val = arr[-1];
    std::cout << "successful";
}



void reaction_for_crash(const int signalnum)
{
    std::cout<<"crash_intercept!\n";
    std::cout<<"detected system exception: ";
    
    switch (signalnum)
    {
        case SIGABRT: std::cout<< "SIGABRT\n"; break;
        case SIGSEGV: std::cout<< "SIGSEGV\n"; break;
        case SIGILL:  std::cout<< "SIGILL\n" ; break;
        case SIGFPE:  std::cout<< "SIGFPE\n" ; break;
        #ifndef _MSC_VER
        case SIGBUS:  std::cout<< "SIGBUS\n" ; break;
        #endif
        default:      std::cout<< "UNKOWN\n" ; break;
    }
    
    signal(signalnum, SIG_DFL);  
    exit(3); 
}



Если вкратце, существует особый вид исключений: системные.

Система догадывается о том, что ваша программа ведет себя не корректно по её поведению: 
например, она пытается сделать чтение там, где не должна была бы читать (выход за пределы диапазона массива).

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

И посылает сбойному приложению сигнал. 

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

В общем почитайте о сигналах.

Так же рекомендую к прочтению о seh exception
https://ru.wikipedia.org/wiki/%D0%A1%D1%82%D1%80%D1%83%D0%BA%D1%82%D1%83%D1%80%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%BD%D0%B0%D1%8F_%D0%BE%D0%B1%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D0%BA%D0%B0_%D0%B8%D1%81%D0%BA%D0%BB%D1%8E%D1%87%D0%B5%D0%BD%D0%B8%D0%B9

Автор: neosapient 10.10.2014, 19:30
Lukkoye, спасибо за ответ.

Но обработчик исключения не сработал в программе собранной VC9.
Может надо флаги какие-нибудь включить?

P.S.
Цитата

Настроил проект на перехват исключений в настройках проекта:
  С\С++ -> Code Generation
  Enable C++ Exeption = Yes With SEH Exceptions (/EHa)

Автор: Lukkoye 10.10.2014, 19:44
Цитата(neosapient @  10.10.2014,  19:30 Найти цитируемый пост)
Lukkoye, спасибо за ответ.

Но обработчик исключения не сработал в программе собранной VC9.
Может надо флаги какие-нибудь включить?


Мне не очевидно, что именно вы имеете ввиду под "исключением". 




Автор: bsa 21.10.2014, 15:43
Если мне память не изменяет, то catch не ловит SEH исключения. Их ловит __catch.
В любом случае, ЛОВИТЬ ДАННЫЕ ИСКЛЮЧЕНИЯ НЕЛЬЗЯ. Если возникло такое исключение, то ты должен исправить его причину в программе, а не подставлять костыли по восстановлению дальнейшей работы программы. Так как не исключено, что дальнейшая работа просто невозможно.

Автор: neosapient 21.10.2014, 17:40
тут вопрос надо рассматривать с такой точки зрения:
как найти место, где программа упала (особенно, если в программе много кода)?

Автор: baldina 21.10.2014, 18:03
Цитата(neosapient @  21.10.2014,  17:40 Найти цитируемый пост)
как найти место, где программа упала

открой Debug->Exceptions и включай Thrown на все подряд

Автор: bsa 22.10.2014, 14:14
Цитата(neosapient @  21.10.2014,  18:40 Найти цитируемый пост)
как найти место, где программа упала (особенно, если в программе много кода)?
это делается под отладчиком. В крайнем случае путем загрузки кор-дампа. Неверный доступ к памяти вылавливается довольно легко. Особенно, в отладочной сборке.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)