vvoid |
Отправлено: 13.05.2005, 16:04 |
|
Машинист паровоза
Группа: Участник
Сообщений: 171
|
Привет!
У меня тут вопрос: а нафига это finly вообще нужно? Я так понимаю, что в этот блок записывается код, который в любом случае должен быть выполнен, правильно? Конструкция try ... catch ... finaly не допустима. Вот, собственно и вопрос: а стоит ли внимание это finaly?
|
|
Sl@Sh |
Отправлено: 13.05.2005, 16:15 |
|
Мастер участка
Группа: Участник
Сообщений: 383
|
Не всегда, но стоит. Например я его постоянно использую при обработке изображения. За блоком try создаю битмап. В блоке try выполняю цикл обработки, а в finally удаляю битмап и.т.п.
Короче желательно использовать всегда, когда есть вероятность ошибки, а нужно обязательно выполнить какой-то код.
|
|
Asher |
Отправлено: 13.05.2005, 16:20 |
|
Мастер участка
Группа: Модератор
Сообщений: 550
|
Тут есть такой момент интересный...
finally выполняется после return, а это иногда очень и очень удобно.
|
|
vvoid |
Отправлено: 16.05.2005, 15:16 |
|
Машинист паровоза
Группа: Участник
Сообщений: 171
|
QUOTE (Asher @ 13/05/2005, 16:20) | finally выполняется после return, а это иногда очень и очень удобно. |
А здесь если можно поподробне
|
|
xim |
Отправлено: 16.05.2005, 21:04 |
|
Станционный диспетчер
Группа: Участник
Сообщений: 143
|
CODE |
void func1()
{
...
throw Exception("bla-bla-bla"); // вылетает во нешнюю функцию
...
}
...
try{
...
func1();
...
}finally{
//handling exceptions
}
| |
|
Asher |
Отправлено: 17.05.2005, 08:06 |
|
Мастер участка
Группа: Модератор
Сообщений: 550
|
Привет.
Код выполняемый в __finally выполняется после return, что делает возможным аналог так жаждуемого многими goto на метку в конце подпрограммы, где можно за собой все подчистить.
К примеру захватили вы какой ресурс, потом проверки всякие и выходы из функции если что не-так. И перед каждым return необходимо ресурс освободить. А если ресурсов не один и return'ов много?
Делаете одно освобождение в секции __finally, а туда вас компилер после return перебросит.
Упрощенно:
CODE |
int Func1(int e_i)
{
static int i = 0;
try{
switch(e_i){
case 0:
return 0;
break;
case 1:
return 1;
break;
default:
return i;
}
}
__finally{
++i;
}
}
|
Здесь статическая переменная это эмулятор захватываемого ресурса и действий с ним после return.
P.S. только на ++i; брекпоинт поставь, а то пошагам можно и проскочить.
|
|
Asher |
Отправлено: 17.05.2005, 08:15 |
|
Мастер участка
Группа: Модератор
Сообщений: 550
|
Да, и еще __finally удобен тем, что не перехватыват исключение, позволяя передать его на следующий уровень, но при этом ваши ресурсы будут корректно осовбождены, даже если возникнет неожиданное исключение в тексте вашей функции.
В смысле или совсем там не ожидали, или не понятно что с этим ислючением делать, т.к. у функции зачастую нет полноты информации всего приложения чтобы определится с действиями при исключительных ситуациях.
|
|
Admin |
Отправлено: 17.05.2005, 09:49 |
|
Владимир
Группа: Администратор
Сообщений: 1190
|
1. QUOTE | нафига это finly вообще нужно |
CODE |
int *c = NULL;
try{
c = new int[10000]; // выделяем под что-то память
....
.... // используем это что-то
....
}__finally{
delete []c; // в любом случае освобождаем память
}
|
Очень удобно в блоке __finally совершать какие-либо
завершающие действия — освобождать память, закрывать
дескрипторы, открытые таблицы, завершать/откатывать
транзакции, восстанавливать пути и пр.
CODE |
try{
...
} __finally {
FileClose(h);
myTable->Close();
if (Transaction->InTransaction) Transaction->Commit();
if (DBase->Connected) DBase->Close();
SetCurrentDir(currentDir);
}
|
2. QUOTE | Конструкция try ... catch ... finaly не допустима |
Ошибаетесь, вот так допустима:
Использование try ... catch ... finaly
CODE |
//---------------------------------------------------------------------------
int TRegParm::getInt(const char *Parm, int Default)
{
try {
reg->RootKey = HKEY_CURRENT_USER;
if (reg->OpenKey(rootKey, false)) {
try { return reg->ReadInteger(Parm); }
catch(...) { }
}
} __finally { reg->CloseKey(); }
return Default;
}/* getInt() */
|
Или вот так:
3. Код ниже — в любом случае (1,2,3,4) мы попадаем в блок __finally
CODE |
try{
..... операторы 1 .....
try{
..... операторы 2 .....
} catch(...){
if(...) throw 1; // операторы 3
.... операторы 4 .....
}
}__finally{
..... этот код всегда выполнится .....
}
|
Отредактировано Admin — 17/05/2005, 09:51
|
|
Admin |
Отправлено: 17.05.2005, 10:05 |
|
Владимир
Группа: Администратор
Сообщений: 1190
|
Советую еще почитать о достаточно удобной функции Abort()
(не путать с abort() )
"Функия Abort() прерывает текущую процедуру и все вызвавшие ее
процедуры, передавая управление на самый верх. Таким образом
это наиболее простой выход из глубоко вложенных процедур.
... Обычное применение EAbort — прерывание вычислений при
выполнении некоторого условия окончания или условия прерывания
пользователем"
|
|
vvoid |
Отправлено: 18.05.2005, 17:28 |
|
Машинист паровоза
Группа: Участник
Сообщений: 171
|
QUOTE (Asher @ 17/05/2005, 08:15) | Да, и еще __finally удобен тем, что не перехватыват исключение, позволяя передать его на следующий уровень, но при этом ваши ресурсы будут корректно осовбождены, даже если возникнет неожиданное исключение в тексте вашей функции.
|
Перебросить исколючение на уровень выше можно и пустым throw в блоке catch
На крайний случай в блоке catch(...) можно и почистить после себя ничего не зная про то какое вообще исключение возникло. Единственный минус — если исключение не произошло — ресурсы поудалять то всё равно надо, значит придётся дублировть содержание блока catch(...)
|
|
Sl@Sh |
Отправлено: 18.05.2005, 17:46 |
|
Мастер участка
Группа: Участник
Сообщений: 383
|
QUOTE (vvoid @ 18/05/2005, 17:28) | Перебросить исколючение на уровень выше можно и пустым throw в блоке catch |
Вас что ещё не убедило столько аргументов ?
Обратитесь тогда к Страуструпу.
|
|
vvoid |
Отправлено: 19.05.2005, 15:00 |
|
Машинист паровоза
Группа: Участник
Сообщений: 171
|
Доводы то нормальные. Да сама идея тоже нормальная, но вот реализована через Ж.
По мне, так идеальным решением было бы создание конструкции
try
{
...
}
catch
{
...
}
finaly
{
...
}
А то сначала try-finaly, внутри — try-catch, Разве это не через Ж.
Кстати, а как с поддержкой нескольких finaly. Судя по тому, что оно выполняется после завершения программы, то ни о какой такой поддержке речь не идёт, или я ошибаюсь?
|
|
Sl@Sh |
Отправлено: 19.05.2005, 16:08 |
|
Мастер участка
Группа: Участник
Сообщений: 383
|
Нескольких вы имеете ввиду вложеных ? Тут поидее можете сколько угодно вкладывать. А вот если вы имеете ввиду несколько finally у одного try, то зачем ? Это не имеет смысла.
|
|
vvoid |
Отправлено: 19.05.2005, 18:36 |
|
Машинист паровоза
Группа: Участник
Сообщений: 171
|
Я как раз таки и имею ввиду конструкцию типа
try
{
try
{
}
finaly
{
}
finaly
{
}
Если эта богодельня (finaly ;-) ) Выполняется после return-а, то какая из них будет выполнятся первой.
А по поводу нескольких finaly у одного try — ну это действительно бред
|
|
Sl@Sh |
Отправлено: 20.05.2005, 06:26 |
|
Мастер участка
Группа: Участник
Сообщений: 383
|
CODE |
try
{
try
{
}
__finally
{
этот может не сработать если до блока try finally что-то ошибочно
}
}
__finally
{
//Этот код выполнится всегда.
} |
Сперва поидее внутренний блок сработает
|
|