Модераторы: Daevaorn

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Поговорим про исключения 
:(
    Опции темы
archimed7592
Дата 29.10.2007, 17:03 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Архимед
****


Профиль
Группа: Завсегдатай
Сообщений: 2531
Регистрация: 12.6.2004
Где: Moscow

Репутация: 58
Всего: 93



Цитата(akizelokro @  29.10.2007,  16:51 Найти цитируемый пост)
Приведи.

Цитата
15.5.1 The terminate() function
In the following situations exception handling must be abandoned for less subtle error handling techniques:
— when the exception handling mechanism, after completing evaluation of the expression to be thrown but before the exception is caught (15.1), calls a user function that exits via an uncaught exception,
— when the exception handling mechanism cannot find a handler for a thrown exception (15.3), or
— when the destruction of an object during stack unwinding (15.2) exits using an exception, or
— when construction or destruction of a non-local object with static storage duration exits using an exception (3.6.2), or
— when execution of a function registered with atexit exits using an exception (18.3), or
— when a throw-expression with no operand attempts to rethrow an exception and no exception is being handled (15.1), or
— when unexpected throws an exception which is not allowed by the previously violated exceptionspecification, and std::bad_exception is not included in that exception-specification (15.5.2), or
— when the implementation’s default unexpected_handler is called (18.6.2.2)
In such cases,
void terminate();
is called (18.6.3).
 In the situation where no matching handler is found, it is implementation-defined whether or not the stack is unwound before terminate() is called. In all other situations, the stack shall not be unwound before terminate() is called. An implementation is not permitted to finish stack unwinding prematurely based on a determination that the unwind process will eventually cause a call to terminate().


.....

18.6.3.1/3
Default behavior: The implementation’s default terminate_handler calls abort().


Цитата(akizelokro @  29.10.2007,  16:51 Найти цитируемый пост)
Я еще учебник не одолел, так что мне стандарт штудировать еще рано.

Стандарт штудировать не обязательно... IIRC об этом же подробно написано у Мейрса.


Цитата(akizelokro @  29.10.2007,  16:51 Найти цитируемый пост)
А учитывая количество литературы, в которой я закопался, и то, что мою работу с меня никто не снимал, просто нет времени.

И тем не менее ты находишь время, получив ответ, проигнорировать его и пофантазировать что будет "если бы, да кабы"...

Добавлено через 1 минуту и 39 секунд
Цитата(Alexeis @  29.10.2007,  16:54 Найти цитируемый пост)
archimed7592, я не вижу чтобы строчка 
Цитата(archimed7592 @  29.10.2007,  16:42 Найти цитируемый пост)
 std::cout << e << std::endl;

Была в защищенной секции...

Какая разница, если до неё выполнение даже не дойдёт smile.

Добавлено через 3 минуты и 32 секунды
Цитата(Alexeis @  29.10.2007,  16:54 Найти цитируемый пост)
вот тогда что произойдет?

Код

archimed7592@PC ~/testlabs/g++
$ cat ./main.cpp
#include <ostream>
#include <iostream>
struct A
{
     ~A()
     {
         throw 1;
     }
};
int main()
{
     try
     {
         A a;
         throw 2;
     }
     catch(int e)
     {
       try
       {
         std::cout << e << std::endl;
       }
       catch(...)
       {
         std::cout << "..." << std::endl;
       }
     }
}

archimed7592@PC ~/testlabs/g++
$ g++ ./main.cpp

archimed7592@PC ~/testlabs/g++
$ ./a.exe

This application has requested the Runtime to terminate it in an unusual way.
Please contact the application's support team for more information.

archimed7592@PC ~/testlabs/g++
$


Добавлено через 4 минуты и 34 секунды
А что ещё может произойти, если ошибка произошла в самом механизме обработки ошибок? 0_о

В Дельфи такого понятия нет, ибо там нет понятия "автоматический объект", как и нет RAII.

Добавлено через 6 минут и 3 секунды
Цитата(Lazin @  29.10.2007,  17:00 Найти цитируемый пост)
Возможно Alexeis, имел ввиду следующее:

Ну с этим всё понятно - а что, в Delphi вложенные блоки обрабатываются как-то иначе?


--------------------
If you have an apple and I have an apple and we exchange apples then you and I will still each have one apple. But if you have an idea and I have an idea and we exchange these ideas, then each of us will have two ideas.
© George Bernard Shaw
PM Jabber   Вверх
archimed7592
Дата 29.10.2007, 17:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Архимед
****


Профиль
Группа: Завсегдатай
Сообщений: 2531
Регистрация: 12.6.2004
Где: Moscow

Репутация: 58
Всего: 93



Вообще говоря, выполнение в блоке catch отличается от выполнения вне блока catch только тем, что внутри catch поведение инструкции throw; имеет предсказуемый результат.
Даже в таких, немного извращённых, случаях:
Код

#include <istream>
#include <ostream>
#include <iostream>

void handleException()
{
    try
    {
        throw;
    }
    catch(int e)
    {
        std::cout << "int: " << e << std::endl;
    }
    catch(double e)
    {
        std::cout << "double: " << e << std::endl;
    }
    catch(...)
    {
        std::cout << "unknown(maybe bool :))" << std::endl;
    }
}

int main()
{
    while(true)
    {
        try
        {
            char c;
            std::cin >> c;
            switch(c)
            {
            case 'i':
            case 'I':
                throw 1;
            case 'd':
            case 'D':
                throw 1.;
            case 'q':
            case 'Q':
                return 0;
            default:
                throw false;
            }
        }
        catch(...)
        {
            handleException();
        }
    }
}


Код

archimed7592@PC ~/testlabs/g++
$ g++ ./main.cpp

archimed7592@PC ~/testlabs/g++
$ ./a.exe
q

archimed7592@PC ~/testlabs/g++
$ ./a.exe
i
int: 1
i
int: 1
d
double: 1
D
double: 1
g
unknown(maybe bool :))
q

archimed7592@PC ~/testlabs/g++
$



--------------------
If you have an apple and I have an apple and we exchange apples then you and I will still each have one apple. But if you have an idea and I have an idea and we exchange these ideas, then each of us will have two ideas.
© George Bernard Shaw
PM Jabber   Вверх
Alexeis
Дата 29.10.2007, 17:49 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Амеба
Group Icon


Профиль
Группа: Админ
Сообщений: 11743
Регистрация: 12.10.2005
Где: Зеленоград

Репутация: 12
Всего: 459



Цитата(archimed7592 @  29.10.2007,  17:03 Найти цитируемый пост)
Ну с этим всё понятно - а что, в Delphi вложенные блоки обрабатываются как-то иначе?

  Да я с исключениями знаком поверхностно. Примерно знаю как их юзать и все, как оно там внутри не вникал. Однако я ничего не слышал про то что внутри блока обработки нельзя вызывать другое исключение...


--------------------
Vit вечная память.

Обсуждение действий администрации форума производятся только в этом форуме

гениальность идеи состоит в том, что ее невозможно придумать
PM ICQ Skype   Вверх
archimed7592
Дата 29.10.2007, 20:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Архимед
****


Профиль
Группа: Завсегдатай
Сообщений: 2531
Регистрация: 12.6.2004
Где: Moscow

Репутация: 58
Всего: 93



Цитата(Alexeis @  29.10.2007,  17:49 Найти цитируемый пост)
Однако я ничего не слышал про то что внутри блока обработки нельзя вызывать другое исключение...

Внутри блока можно smile.

Когда генерируется исключение, все автоматические объекты из данной области видимости уничтожаются(называются отмоткой стека). Под уничтожением понимается отработка деструкторов. Это происходит ДО входа в блок catch. Т.о., если во время этой отмотки стека из одного из деструкторов вывалится исключение(наружу), то сработает terminate, поведение которого по умолчанию - abort(abnormal termination).


--------------------
If you have an apple and I have an apple and we exchange apples then you and I will still each have one apple. But if you have an idea and I have an idea and we exchange these ideas, then each of us will have two ideas.
© George Bernard Shaw
PM Jabber   Вверх
Alexeis
Дата 29.10.2007, 21:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Амеба
Group Icon


Профиль
Группа: Админ
Сообщений: 11743
Регистрация: 12.10.2005
Где: Зеленоград

Репутация: 12
Всего: 459



Цитата(archimed7592 @  29.10.2007,  20:27 Найти цитируемый пост)
Когда генерируется исключение, все автоматические объекты из данной области видимости уничтожаются(называются отмоткой стека).

 Т.е. уничтожаются все статические объекты объявленные в этом блоке (в блоке try)?


--------------------
Vit вечная память.

Обсуждение действий администрации форума производятся только в этом форуме

гениальность идеи состоит в том, что ее невозможно придумать
PM ICQ Skype   Вверх
archimed7592
Дата 29.10.2007, 22:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Архимед
****


Профиль
Группа: Завсегдатай
Сообщений: 2531
Регистрация: 12.6.2004
Где: Moscow

Репутация: 58
Всего: 93



Цитата(Alexeis @  29.10.2007,  21:50 Найти цитируемый пост)
 Т.е. уничтожаются все статические объекты объявленные в этом блоке (в блоке try)? 

Не статические, а автоматические smile. У статических объектов деструкторы отрабатывают по её завершению(грубо говоря, по выходу из main).
И не только те, что объявлены в этом блоке, но во всех других блоках видимости, которые покидает исключение по пути к своему обработчику.
Код

#include <istream>
#include <ostream>
#include <iostream>

struct Logger
{
    explicit Logger(int value)
     : value(value)
    {
        std::cout << "Logger(" << value << ")" << std::endl;
    }
    
    ~Logger()
    {
        std::cout << "~Logger(" << value << ")" << std::endl;
    }
private:
    int value;
};
        
int main()
{
    Logger log1(1), log2(2);
    try
    {
        Logger log3(3), log4(4);
        try
        {
            Logger log5(5);
            throw 1;
        }
        catch(int e)
        {
            std::cout << "catch " << e << std::endl;
        }
        try
        {
            Logger log6(6);
        }
        catch(int e)
        {
            std::cout << "catch " << e << std::endl;
        }
        try
        {
            Logger log7(7);
            throw 2.0;
        }
        catch(int e)
        {
            std::cout << "catch int " << e << std::endl;
        }
    }
    catch(double e)
    {
        std::cout << "catch double " << e << std::endl;
    }
    Logger log8(8), log9(9);
    
}

Код

archimed7592@PC ~/testlabs/g++
$ g++ ./main.cpp

archimed7592@PC ~/testlabs/g++
$ ./a.exe
Logger(1)
Logger(2)
Logger(3)
Logger(4)
Logger(5)
~Logger(5)
catch 1
Logger(6)
~Logger(6)
Logger(7)
~Logger(7)
~Logger(4)
~Logger(3)
catch double 2
Logger(8)
Logger(9)
~Logger(9)
~Logger(8)
~Logger(2)
~Logger(1)

archimed7592@PC ~/testlabs/g++
$

Обрати внимание, что уничтожается не только 7, но 4, 3, ибо их область видимости тоже заканчивается во время проброса исключения и, соответственно, отмотки стека.

Добавлено через 2 минуты и 19 секунд
На принципе отмотки стека и основан RAII - это замена вашему finally(вместо него деструктор)... Только вот finally можно забыть написать, а деструктор автоматического объекта вызовется автоматически по выходу из области видимости smile. Будь то исключение, обычной ход выполнения, goto или ещё что-нибудь.

Это сообщение отредактировал(а) archimed7592 - 29.10.2007, 22:07


--------------------
If you have an apple and I have an apple and we exchange apples then you and I will still each have one apple. But if you have an idea and I have an idea and we exchange these ideas, then each of us will have two ideas.
© George Bernard Shaw
PM Jabber   Вверх
Alexeis
Дата 29.10.2007, 22:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Амеба
Group Icon


Профиль
Группа: Админ
Сообщений: 11743
Регистрация: 12.10.2005
Где: Зеленоград

Репутация: 12
Всего: 459



Цитата(archimed7592 @  29.10.2007,  22:07 Найти цитируемый пост)
Обрати внимание, что уничтожается не только 7, но 4, 3, ибо их область видимости тоже заканчивается во время проброса исключения и, соответственно, отмотки стека.

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


--------------------
Vit вечная память.

Обсуждение действий администрации форума производятся только в этом форуме

гениальность идеи состоит в том, что ее невозможно придумать
PM ICQ Skype   Вверх
Alexeis
Дата 29.10.2007, 22:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Амеба
Group Icon


Профиль
Группа: Админ
Сообщений: 11743
Регистрация: 12.10.2005
Где: Зеленоград

Репутация: 12
Всего: 459



В делфях все не так работает. Если возникает исключение, то обработка происходит внутри текущего блока. Он как бы изолирован и не видит внешнего блока. Только если исключение будет в самой обработке, тогда вызовется внешний обработчик. Для блока Try может быть только 1 except или 1 finally (но не одновременно)

Пример
Код

var
  c1, c2 : integer;
begin
  try
    c1 := 7;
    c2 := 0;
    try
      c1 := c1 div c2;
      c1 := 7;
    finally
      raise EAccessViolation.Create('абшибка');
      showmessage('выполнился finally');
    end;

  except
   // showmessage('выполнился except');
    on EAccessViolation do showmessage('выполнился EAccessViolation');
    on EDivByZero       do showmessage('выполнился EDivByZero');
  end;


Сначала сработает finally, но сообщение 'выполнился finally' не выйдет, так как сгенериться AV и только в этом случае выполниться except.
Обработка разных типов исключений определяется в рамках одного блока, т.е. в данном случае 
"on EDivByZero       do showmessage('выполнился EDivByZero');" никогда не выполниться потому, что исключение EDivByZero считается уже отработанным в блоке finally.

  Т.е. схема более простая и прозрачная. Ну про статические объекты говорить тут нечего, так как их попросту нет, да и вообще в блоках нельзя объявлять переменные, потому они будут существовать до конца работы функции.


--------------------
Vit вечная память.

Обсуждение действий администрации форума производятся только в этом форуме

гениальность идеи состоит в том, что ее невозможно придумать
PM ICQ Skype   Вверх
akizelokro
Дата 31.10.2007, 10:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Крокодил
**


Профиль
Группа: Участник
Сообщений: 761
Регистрация: 30.7.2007

Репутация: 1
Всего: 5



Цитата

IIRC об этом же подробно написано у Мейрса.


За ответ спасибо. За ссылку на Мейерса тоже, но чтить его буду после одоления текущего учебника.

Иными словами, если во время раскрутки стека возбуждается второе исключение, то программа падает, а я теряю контроль над своим кодом, даже если казалось бы делаю все правильно. Неприятно.

Вот и ответ автору темы на его поставленные вопросы (большинство из них).


--------------------
a = a + b; b = a - b; a = a - b;
PM MAIL   Вверх
archimed7592
Дата 31.10.2007, 11:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Архимед
****


Профиль
Группа: Завсегдатай
Сообщений: 2531
Регистрация: 12.6.2004
Где: Moscow

Репутация: 58
Всего: 93



Цитата(akizelokro @  31.10.2007,  10:48 Найти цитируемый пост)
, даже если казалось бы делаю все правильно.

А что ты понимаешь под словами "делаю всё правильно"?
Грубо говоря, зачем выпускать исключение из деструктора можешь объяснить? Ты же потом уже не сможешь уничтожить объект "до конца".


--------------------
If you have an apple and I have an apple and we exchange apples then you and I will still each have one apple. But if you have an idea and I have an idea and we exchange these ideas, then each of us will have two ideas.
© George Bernard Shaw
PM Jabber   Вверх
akizelokro
Дата 31.10.2007, 11:23 (ссылка)    | (голосов:2) Загрузка ... Загрузка ... Быстрая цитата Цитата


Крокодил
**


Профиль
Группа: Участник
Сообщений: 761
Регистрация: 30.7.2007

Репутация: 1
Всего: 5



я говорю про то, что если при раскрутке стека уничтожается локальный объект с деструктором вида

Код

~Something()
{
  try
  {
    ....
  }
  catch(const SomeException& se)
  {
    ..
  }
}


или с деструктором в функциональном виде, то даже несмотря на наличие обработки исключения, на которую я надеюсь, программа все равно отрубится. Согласно стандарту. Для динамических объектов это не так.



Это сообщение отредактировал(а) akizelokro - 31.10.2007, 11:36


--------------------
a = a + b; b = a - b; a = a - b;
PM MAIL   Вверх
UnrealMan
Дата 31.10.2007, 11:56 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 722
Регистрация: 30.3.2006

Репутация: 27
Всего: 32



Цитата(akizelokro @  31.10.2007,  11:48 Найти цитируемый пост)
Иными словами, если во время раскрутки стека возбуждается второе исключение, то программа падает, а я теряю контроль над своим кодом, даже если казалось бы делаю все правильно. Неприятно.

Неправда. В C++ одновременно может быть хоть сто необработанных исключений. Если их вовремя ловить, то программа будет вполне себе благополучно работать.
PM MAIL   Вверх
bsa
Дата 31.10.2007, 12:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Модератор
Сообщений: 9185
Регистрация: 6.4.2006
Где: Москва, Россия

Репутация: 63
Всего: 196



Цитата(akizelokro @ 31.10.2007,  11:23)
я говорю про то, что если при раскрутке стека уничтожается локальный объект с деструктором вида

Код

~Something()
{
  try
  {
    ....
  }
  catch(const SomeException& se)
  {
    ..
  }
}


или с деструктором в функциональном виде, то даже несмотря на наличие обработки исключения, на которую я надеюсь, программа все равно отрубится. Согласно стандарту. Для динамических объектов это не так.

В данном случае код вполне легальный.
Программа убивается через std::terminate(), когда исключение выходит за пределы деструктора!!!!
т.е.
Код
#include <iostream>
struct A
{
     ~A() { 
          try {
               throw 1;
          } catch(int) {
               std::cout << "A" << std::endl;
          }
     }
};
struct B
{
     ~B() { 
          try {
               throw "";
          } catch(int) {
               std::cout << "B" << std::endl;
          }
     }
};

main()
{
        B b;
        A a;
}
Результат работы будет следующий:
Код
$ ./a.out 
A
terminate called after throwing an instance of 'char const*'
Аварийный останов


Добавлено через 2 минуты и 26 секунд
В данном примере, в деструкторе класса B было кинуто исключения типа const char *, а catch стоял только на исключения типа int. В итоге, исключение вышло из пределов деструктора, а так как деструктор не закончил выполнение, была вызвана std::terminate().
PM   Вверх
akizelokro
Дата 31.10.2007, 12:59 (ссылка)    | (голосов:2) Загрузка ... Загрузка ... Быстрая цитата Цитата


Крокодил
**


Профиль
Группа: Участник
Сообщений: 761
Регистрация: 30.7.2007

Репутация: 1
Всего: 5



Код правильный, но не о том. С самого начала рассматривается ситуация, когда возбуждено исключение, назовем его первичным. Происходит раскрутка стека, и в ходе этой раскрутки стека идет второе исключение при уничтожении локального объекта (в деструкторе). Стандарт гласит (если мой перевод верен), что в этом случае программа вызовет функцию terminate (до или после обработки вторичного исключения - уже не так важно). И это будет даже когда логика деструктора не подразумевает прекращения дальнейшего выполнения программы и возникшее в деструкторе исключение в том же самом деструкторе должно без лишнего шума обработаться. В твоем же коде идет обычная обработка двух невложенных исключений.

Это сообщение отредактировал(а) akizelokro - 31.10.2007, 13:02


--------------------
a = a + b; b = a - b; a = a - b;
PM MAIL   Вверх
akizelokro
Дата 31.10.2007, 13:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Крокодил
**


Профиль
Группа: Участник
Сообщений: 761
Регистрация: 30.7.2007

Репутация: 1
Всего: 5



Кстати, такой код 

Код

#include <ostream>
#include <iostream>
struct A
{
     ~A()
     {
         try
         {
            throw 1;
         }
         catch(int e)
         {
             std::cout << e << std::endl;
         }
     }
};

int main()
{
     try
     {
         A a;
         throw 2;
     }
     catch(int e)
     {
         std::cout << e << std::endl;
     }
     std::cout << "Программирование - работа с ошибками:-)" << std::endl;
     return 0;
}


в МSVC++ 6 добрался до благополучного завершения. Хмык, нужно садиться за английский.


--------------------
a = a + b; b = a - b; a = a - b;
PM MAIL   Вверх
Страницы: (5) Все 1 2 [3] 4 5 
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++:Общие вопросы"
Earnest Daevaorn

Добро пожаловать!

  • Черновик стандарта C++ (за октябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика(4.4мб).
  • Черновик стандарта C (за сентябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика (3.4мб).
  • Прежде чем задать вопрос, прочтите это и/или это!
  • Здесь хранится весь мировой запас ссылок на документы, связанные с C++ :)
  • Не брезгуйте пользоваться тегами [code=cpp][/code].
  • Пожалуйста, не просите написать за вас программы в этом разделе - для этого существует "Центр Помощи".
  • C++ FAQ

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Earnest Daevaorn

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.1271 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.