Источник http://mylnye-grezi.ru.
C++ Builder
| Главная | Уроки | Статьи | FAQ | Форум | Downloads | Литература | Ссылки | RXLib | Диски |

 
finаly, А стоит ли?
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, а это иногда очень и очень удобно. biggrin.gif
vvoid
Отправлено: 16.05.2005, 15:16


Машинист паровоза

Группа: Участник
Сообщений: 171



QUOTE (Asher @ 13/05/2005, 16:20)
finally выполняется после return, а это иногда очень и очень удобно. biggrin.gif

А здесь если можно поподробне
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; брекпоинт поставь, а то пошагам можно и проскочить. biggrin.gif
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 — ну это действительно бред smile.gif
Sl@Sh
Отправлено: 20.05.2005, 06:26


Мастер участка

Группа: Участник
Сообщений: 383



CODE

try
{
  try
  {

  }
  __finally
  {
     этот может не сработать если до блока try finally что-то ошибочно  
  }
}
__finally
{
//Этот код выполнится всегда.
}


Сперва поидее внутренний блок сработает

Вернуться в Вопросы программирования в C++Builder