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


Автор: regis 4.2.2008, 15:46
Собственно, возник такой вопрос.
Предположим, что глубоко в последовательности вызовов может быть возбуждено исключение (см. пример):

Код


void inner () {
// ...
throw Exception (...);
}    // inner

void work_func () {
// ...
inner ();
// ...
}    // work_func

void outer () {

try {
    // ...
    work_func ();
    // ...
    } catch (Exception excpt) {
        // обработка excpt здесь...
    };

}    // outer



Вопрос в том, как обработать ненормальное завершение работы work_func.
Т.е. реально ли создать какой-нибудь обработчик, который будет вызываться,
если ее выполнение было прервано по throw из inner?? Насколько я понимаю, через
определение специальных классов с деструкторами этого можно добиться -- но
мне интересно, есть ли более короткий путь.

Автор: xvr 4.2.2008, 15:50
Цитата(regis @ 4.2.2008,  15:46)
Собственно, возник такой вопрос.
Предположим, что глубоко в последовательности вызовов может быть возбуждено исключение (см. пример):

Код


void inner () {
// ...
throw Exception (...);
}    // inner

void work_func () {
// ...
inner ();
// ...
}    // work_func

void outer () {

try {
    // ...
    work_func ();
    // ...
    } catch (Exception excpt) {
        // обработка excpt здесь...
    };

}    // outer



Вопрос в том, как обработать ненормальное завершение работы work_func.
Т.е. реально ли создать какой-нибудь обработчик, который будет вызываться,
если ее выполнение было прервано по throw из inner?? Насколько я понимаю, через
определение специальных классов с деструкторами этого можно добиться -- но
мне интересно, есть ли более короткий путь.

Ну например так:
Код

void work_func () {
 try {
// ...
inner ();
// ...
 } 
 catch(...)
 {
   // do something
   throw;
 }
}    // work_func

Автор: archimed7592 4.2.2008, 18:25
Лучше использовать RAII.

Автор: Alek86 4.2.2008, 18:52
Цитата(archimed7592 @  4.2.2008,  18:25 Найти цитируемый пост)
Лучше использовать RAII.

даже если в
Код

catch(...)
 {
   // do something
   throw;
 }

в // do something будут TRACE'ы для отладки?
лично мне лень тогда классы добавлять...

Автор: archimed7592 4.2.2008, 18:59
Цитата(Alek86 @  4.2.2008,  18:52 Найти цитируемый пост)
в // do something будут TRACE'ы для отладки?

 smile 
Я переодически использую самописный велосипед LogOnFailure logger(LOG_MSG("bla-bla-bla"));.

Автор: Alek86 4.2.2008, 19:03
прогнал (

а если такая фича и в бусте есть (уверен, есть), то я тоже за RAII во всех случаях (кроме когда уж совсем лень)

Автор: archimed7592 5.2.2008, 03:03
Цитата(Alek86 @  4.2.2008,  19:03 Найти цитируемый пост)
уверен, есть

В бусте я logging capabilities не заметил... Найдёшь - отпишись smile.

Автор: Daevaorn 5.2.2008, 03:44
Цитата(archimed7592 @  5.2.2008,  04:03 Найти цитируемый пост)
В бусте я logging capabilities не заметил... Найдёшь - отпишись 

http://www.torjo.com/log2/doc/html/index.html

Автор: archimed7592 5.2.2008, 04:48
Daevaorn, интересненько smile.
А есть ли где-нибудь информация о том, почему библиотека не включена в буст(видимо есть какие-то недоработки?), когда ориентировочно собираются включить, собираются ли вообще?

Автор: regis 5.2.2008, 15:26
Всем спасибо, кто ответил.

RAII -- это, как я понимаю, и есть то, о чем я говорил выше. С этим подходом есть проблема: в work_func может быть много локальных переменных и соответственно много чего с ним необходимо сделать для корректной финализации. Т.е. завернуть это в конструкторы/деструкторы объекта вряд ли получится.

Более симпатично выглядит идея с re-throw. Однако, можно ли throw без аргументов вызвать из другого места, кроме обработчика в catch?
Например, вот такой подход:

Код


void work_func () {
bool caught_exception = false;

// ... пролог ...


try {
   inner ();
   } catch (Exception excpt) {
    caught_exception = true;
    }

// ... эпилог ...

if (caught_exception) throw;
}    // work_func



-- такое сработает или нет?


Автор: xvr 5.2.2008, 17:30
Цитата(regis @ 5.2.2008,  15:26)
Всем спасибо, кто ответил.

RAII -- это, как я понимаю, и есть то, о чем я говорил выше. С этим подходом есть проблема: в work_func может быть много локальных переменных и соответственно много чего с ним необходимо сделать для корректной финализации. Т.е. завернуть это в конструкторы/деструкторы объекта вряд ли получится.

Более симпатично выглядит идея с re-throw. Однако, можно ли throw без аргументов вызвать из другого места, кроме обработчика в catch?

Можно, но это место должно быть вложенно в блок catch (статически или динамически)

Цитата

Например, вот такой подход:

Код


void work_func () {
bool caught_exception = false;

// ... пролог ...


try {
   inner ();
   } catch (Exception excpt) {
    caught_exception = true;
    }

// ... эпилог ...

if (caught_exception) throw;
}    // work_func



-- такое сработает или нет?
Нет

Автор: archimed7592 5.2.2008, 21:04
Цитата(regis @  5.2.2008,  15:26 Найти цитируемый пост)
такое сработает или нет?

Нет. Сработает такое:
Код

void work_func () {
bool caught_exception = false;
// ... пролог ...
try {
   inner ();
   } catch (Exception excpt) {
      epilog(true);
    }
epilog(false);


void epilog(bool rethrow = false)
{
    // ...

    if (rethrow) throw;
}


К слову, для того и нужен RAII - он отработает и в случае нормального течения обстоятельств, так и в случае исключительной ситуации.


Цитата(regis @  5.2.2008,  15:26 Найти цитируемый пост)
в work_func может быть много локальных переменных и соответственно много чего с ним необходимо сделать для корректной финализации.

Налицо отсутствие гарантии безсбойности - это не есть хорошо и эту ф-цию нужно переписать и/или разбить на несколько ф-ций...

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