49 / 25 / 2
Регистрация: 09.06.2008
Сообщений: 227
1

Выполнять определенные действия при любом выходе из функции

25.09.2012, 23:24. Показов 3698. Ответов 41
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Есть функция, в которой ряд ветвлений и return'ов... при этом хотелось бы при каждом return'е выполнять определенные действия (обнуление флагов, освобождение памяти и еще ряд операций).
Как такое грамотнее реализовать?
1
Лучшие ответы (1)
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
25.09.2012, 23:24
Ответы с готовыми решениями:

Как не выполнять действия при определенном условии?
программа работает нормально, проблема только в одном при выводе сообщения "неправильно введено...

Определенные действия при подключении флэшки
if ( Message.Msg == WM_DEVICECHANGE && Message.WParam == 0x8000 ) { char DiskLabel; ...

Выполнять действия через определенные интервалы таймера
Нужно считывать информацию с таймера и в соответствии со временем делать клик мышкой. Таймер до...

Написать автотест, который будет выполнять определенные действия
Здравствуйте! В общем такая тема, на работе сильно требуют знания С# и выдали задачку для освоения....

41
Супер-модератор
Эксперт Pascal/DelphiАвтор FAQ
32830 / 21168 / 8147
Регистрация: 22.10.2011
Сообщений: 36,429
Записей в блоге: 8
26.09.2012, 00:34 2
Вообще-то лучше писать функции так, чтобы в них был единственный return.

В самом крайнем случае можно обернуть всё тело функции в try {здесь тело функции} /__finally {действия при выходе}, тогда перед выходом по return-у выполнится то, что записано в блоке __finally. Но это - костыль.
1
435 / 402 / 57
Регистрация: 06.02.2012
Сообщений: 1,384
26.09.2012, 00:41 3
Лучший ответ Сообщение было отмечено как решение

Решение

Часть кода которую нужно сделать написать в конце ф-ции, а вместо ретурнов в ф-ции писать goto туда где стоит эта часть кода.
3
Практикантроп
4824 / 2717 / 525
Регистрация: 23.09.2011
Сообщений: 5,777
26.09.2012, 09:20 4
Если в функции множество ветвлений, то резонно в самом начале определить переменную (скажем - steps), которой в каждой ветви присваивается некое значение. А при завершении обработки эта переменная анализируется (типа swich - case... снова ветвление )
2
4043 / 2332 / 292
Регистрация: 03.02.2011
Сообщений: 5,066
Записей в блоге: 10
26.09.2012, 15:14 5
Цитата Сообщение от UI Посмотреть сообщение
Вообще-то лучше писать функции так, чтобы в них был единственный return.
Обеими руками за

Вопрос на засыпку: а почему вообще в функции много return'ов оказалось? Потому что либо при ветвлении функция должна возвращать различные значения, либо возвращать она ничего не должна, а автор просто не умеет работать с условиями или циклами. В первом случае нужно модифицировать возвращаемое значение в зависимости от ветвлений и в конце возвращать его один раз, выполняя при этом некие побочные действия. Во втором - выпрямлять руки.
1
435 / 402 / 57
Регистрация: 06.02.2012
Сообщений: 1,384
26.09.2012, 16:04 6
Цитата Сообщение от BRcr Посмотреть сообщение
Вопрос на засыпку: а почему вообще в функции много return'ов оказалось?
Пример на вскидку. В начале ф-ции проверяем корректность переданных параметров. Причем сначала мы делаем быстрые проверки в одном условии. Если не прошли, то нужен ретурн. Затем мы делаем более сложные проверки, с расчетом некоего промежуточного параметра. Если не прошли то ретурн. Если прошли считаем следующий параметр и т.д.
Я бы сделал так:
C++
1
2
3
4
5
6
7
8
9
10
11
void Func(int x, int y)
{ if(x<0 ||  y<0)
    return;
  int p=x+y; // здесь может быть гораздо более сложный расчет
  if(p<5)
    return;
  p=x*y; // здесь может быть гораздо более сложный расчет
  if(p<10)
    return;
  .../// тут пошло тело ф-ции
}
Так делать ресурсоемко, т.к. расчет параметров может и не понадобится вовсе:
C++
1
2
3
4
5
6
7
void Func(int x, int y)
{ int p1=x+y; // здесь может быть гораздо более сложный расчет
  int p2=x*y; // здесь может быть гораздо более сложный расчет
  if( !(x<0 || y<0 || p1<5 || p2<10) )
  {.../// тут пошло тело ф-ции
  }
}
А так неудобно тянуть отступы через всю ф-цию:
C++
1
2
3
4
5
6
7
8
9
10
11
void Func(int x, int y)
{ if(x>=0 &&  y>=0)
  { int p=x+y; // здесь может быть гораздо более сложный расчет
    if(p>=5)
    { p=x*y; // здесь может быть гораздо более сложный расчет
      if(p>=10)
      { .../// тут пошло тело ф-ции
      }
    } 
  }
}
И что в таком случае вы предложите?
1
Супер-модератор
Эксперт Pascal/DelphiАвтор FAQ
32830 / 21168 / 8147
Регистрация: 22.10.2011
Сообщений: 36,429
Записей в блоге: 8
26.09.2012, 16:26 7
Цитата Сообщение от gumi250 Посмотреть сообщение
что в таком случае вы предложите?
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
void Func(int x, int y)
{
do {
   if(x<0 || y<0)
      break;
 
   int p=x+y; // здесь может быть гораздо более сложный расчет
   if(p<5)
      break;
 
   p=x*y; // здесь может быть гораздо более сложный расчет
   if(p<10)
      break;
 
   // тут пошло тело ф-ции
} while(0);
// тут - единственная точка выхода из функции, перед которой - очистка всего, что надо
}
P.S. если уж пишешь на С++ - то используй RAII, тогда не надо будет отдельно делать очистку ресурсов.
0
Диссидент
Эксперт C
27706 / 17322 / 3812
Регистрация: 24.12.2010
Сообщений: 38,979
26.09.2012, 16:35 8
Цитата Сообщение от nick42 Посмотреть сообщение
Если в функции множество ветвлений, то резонно в самом начале определить переменную (скажем - steps), которой в каждой ветви присваивается некое значение. А при завершении обработки эта переменная анализируется (типа swich - case... снова ветвление )
Хоть goto и является в некоторых странах персоной нот грата, в данном случае я всеми четырьмя лапами ЗА. И код это нисколько не запутывает, а скорее проясняет, и вообще goto вниз некоторыми не слишком упертыми теоретиками считается вполне допустимым...

Добавлено через 2 минуты
Извиняюсь, перепутал цитаты. Имел в виду эту
Цитата Сообщение от gumi250 Посмотреть сообщение
Часть кода которую нужно сделать написать в конце ф-ции, а вместо ретурнов в ф-ции писать goto туда где стоит эта часть кода.
1
435 / 402 / 57
Регистрация: 06.02.2012
Сообщений: 1,384
26.09.2012, 16:45 9
UI, и чем ваш пример с do, break, while лучше ретурнов? Тем что добавляет ненужный do и отступ на протяжении все ф-ци. На мой взляд ваш вариант выглядbт более запутанным. А если я хочу в самом теле ф-ции (после всех начальных проверок) тоже использовать do, while или for из которого иногда тоже хочу выйти ретурном? Мой вариант сработает ваш нет.

По поводу goto и его не применимости. Не могу сдержаться и не задать вопрос. Как написать такой пример без goto:
C++
1
2
3
4
5
6
7
8
/// ищем первую ячейку в матрице равную нулю
int y,x; 
for(y=0; y<Height; y++)
{ for(x=0; x<Width; x++)
  { if(Data[y][x]==0) goto EndFind; // все нашли дальше можно не искать
  }
}
EndFind: .../// здесь в у и х хранятся координаты найденой ячейки
1
Почетный модератор
Эксперт С++
5850 / 2861 / 392
Регистрация: 01.11.2011
Сообщений: 6,907
26.09.2012, 16:49 10
Цитата Сообщение от BRcr Посмотреть сообщение
В первом случае нужно модифицировать возвращаемое значение в зависимости от ветвлений и в конце возвращать его один раз, выполняя при этом некие побочные действия.
Чего это вдруг? Пусть возвращает сколько требуется/хочется значений. А потом уже в другой функции разбираться с результатами. К примеру GetKeyState() возвращает аж четыре разных результата. И что? Хочется ей - пусть возвращает хоть миллион.
Или я уже с дурацкими замечаниями опоздал?
0
435 / 402 / 57
Регистрация: 06.02.2012
Сообщений: 1,384
26.09.2012, 16:58 11
UI, а если я передаю в ф-цию массив и хочу проверить чтобы в переданном массиве не было нулевых элементов и если есть хоть один (когда найду первый равный нулю) то ретурн, тогда что? Мой вариант сработает ваш break нет.
0
return (true);
1976 / 1111 / 221
Регистрация: 19.04.2011
Сообщений: 2,345
26.09.2012, 17:18 12
Цитата Сообщение от SatanaXIII Посмотреть сообщение
К примеру GetKeyState() возвращает аж четыре разных результата. И что?
А судя по описанию GetKeyState возвращает один результат SHORT
Цитата Сообщение от gumi250 Посмотреть сообщение
а если я передаю в ф-цию массив и хочу проверить чтобы в переданном массиве не было нулевых элементов и если есть хоть один (когда найду первый равный нулю) то ретурн, тогда что?
C++
1
2
3
4
5
6
bool do_we_have_zero_in_array=false;
for (...)
{
 if (array[i]==0) { do_we_have_zero_in_array=true; break;}
}
return (do_we_have_zero_in_array);
И вот еще
C++
1
2
3
4
5
6
7
8
9
/// èùåì ïåðâóþ ÿ÷åéêó â ìàòðèöå ðàâíóþ íóëþ
bool endLoop = false;
int y,x;
for(y=0; y<Height && !endLoop; y++)
{ for(x=0; x<Width && !endLoop; x++)
  { if(Data[y][x]==0) endLoop = true; // âñå íàøëè äàëüøå ìîæíî íå èñêàòü
  }
}
EndFind:
Добавлено через 11 минут
Ну и чтобы далеко не ходить
В чем преимущества такого подхода? А в том, что когда я смотрю на эту чудовищную конструкцию, я сразу вижу, что из этих циклов возможен досрочный выход. И этот досрочный выход произойдет, если переменная endLoop пример значение true. Если я буду искать, где же в программе такое присваивание, я быстро пойму, при каких обстоятельствах осуществляется досрочный выход.

Если же будет goto, то я могу и не догадываться, что там вообще возможно досрочное прекращение, пока не изучу досконально весь код. При этом, встретив метку, я буду думать, откуда на нее есть переходы, потому что они могут быть не только из цикла, но и откуда угодно, хоть сверху, хоть снизу. Это очень сильно запутывает код.
0
Диссидент
Эксперт C
27706 / 17322 / 3812
Регистрация: 24.12.2010
Сообщений: 38,979
26.09.2012, 17:28 13
gumi250, Ну, можно сделать и так
C
1
2
3
4
5
6
7
8
9
10
/// ищем первую ячейку в матрице равную нулю
int y,x; 
for(y=0; y<Height; y++)
{ for(x=0; x<Width; x++)
  { if(Data[y][x]==0) break; // все нашли дальше можно не искать
  }
  if (x < Width) break;
}
if (y<Height)... // Найдено
}
Но это ничем не лучше предложенного Вами. А в более сложных случаях - значительно запутанней
0
Почетный модератор
Эксперт С++
5850 / 2861 / 392
Регистрация: 01.11.2011
Сообщений: 6,907
26.09.2012, 17:31 14
Цитата Сообщение от mimicria Посмотреть сообщение
А судя по описанию GetKeyState возвращает один результат SHORT
Ах вы вон куда полезли.
*ретируюсь поджав хвост.
0
Day
26.09.2012, 17:45
  #15

Не по теме:


Друзья! Вам не кажется, что мы вступаем на тропу "священной войны"... :)

0
4043 / 2332 / 292
Регистрация: 03.02.2011
Сообщений: 5,066
Записей в блоге: 10
26.09.2012, 17:46 16
Цитата Сообщение от SatanaXIII Посмотреть сообщение
Или я уже с дурацкими замечаниями опоздал?
Ну да, есть такое малость. Смотри первый пост в теме - поймешь, зачем один return нужен.
Цитата Сообщение от gumi250 Посмотреть сообщение
Пример на вскидку. В начале ф-ции проверяем корректность переданных параметров. Причем сначала мы делаем быстрые проверки в одном условии. Если не прошли, то нужен ретурн.
Нет совершенно никакой необходимости доказывать всем, что куча return'ов на твой взгляд удобнее, читабельней и вообще единственно возможный вариант и прочая, прочая... ТС озвучил вполне конкретное желание - один return и возможность до этого освободить память вне зависимости от логических ветвлений. Желание просто поспорить представляется несколько за рамками темы.
0
Почетный модератор
Эксперт С++
5850 / 2861 / 392
Регистрация: 01.11.2011
Сообщений: 6,907
26.09.2012, 18:00 17
Цитата Сообщение от BRcr Посмотреть сообщение
Ну да, есть такое малость. Смотри первый пост в теме - поймешь, зачем один return нужен.
Уже понял. Я молчу.

Day, добро пожаловать ко мне под пыльную кровать.

Ну а по теме: было бы неплохо все таки в конце увидеть обобщенный результат.
0
435 / 402 / 57
Регистрация: 06.02.2012
Сообщений: 1,384
27.09.2012, 00:11 18
BRcr, нет желания просто поспорить, есть желание посмотреть как делают другие, может они делают это лучше меня.
Возможно вы считаете этот вариант кода лучшим:
C++
1
2
3
4
5
6
7
8
9
/// ищем первую ячейку в матрице равную нулю
bool endLoop = false;
int y,x;
for(y=0; y<Height && !endLoop; y++)
{ for(x=0; x<Width && !endLoop; x++)
  { if(Data[y][x]==0) endLoop = true; // все нашли дальше можно не искать
  }
}
EndFind:
Что за ерунда вместо goto употреблять if. Если матрица 1000х1000, то я сделаю до 10Е6 лишних сравнений просто потому что не использую goto. Если мне язык дал простую возможность написать более быстрый код, то я это сделаю, а не буду следовать каким то стериотипам.
Может вы видя do в начале ф-ции думаете, и о досрочном ретурне, а я думаю о цикле в который зачем то заключена вся ф-ция.
Да goto не совсем читаем, но иногда другие варианты еще хуже.
1
4043 / 2332 / 292
Регистрация: 03.02.2011
Сообщений: 5,066
Записей в блоге: 10
27.09.2012, 00:30 19
Цитата Сообщение от gumi250 Посмотреть сообщение
Что за ерунда вместо goto употреблять if. Если матрица 1000х1000, то я сделаю до 10Е6 лишних сравнений просто потому что не использую goto.
Глупость. Лишних сравнений не будет, да и быть не может. Прочитай код повнимательней - что с goto, что с endloop суть не меняется: по исполнении условия циклы прерываются. Вопрос использования или неиспользования goto - это вопрос персонального удобства, на вкус и цвет, как говорится.
Любой алгоритм можно оформить одинаково эффективно, используя либо флажки, либо goto, либо break, либо еще чего...
0
435 / 402 / 57
Регистрация: 06.02.2012
Сообщений: 1,384
27.09.2012, 00:34 20
Как это не будет лишних сравнений???
А чем тогда отличаются эти два участка кода?
C++
1
2
for(y=0; y<Height; y++)
{ for(x=0; x<Width; x++)
C++
1
2
for(y=0; y<Height && !endLoop; y++)
{ for(x=0; x<Width && !endLoop; x++)
Они отличаются наличием лишней проверки endLoop на каждый такт цикла
2
27.09.2012, 00:34
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
27.09.2012, 00:34
Помогаю со студенческими работами здесь

Как можно заставить программу выполнять определенные действия после нажатия клавиши ENTER
кто-нибудь может подсказать!! я новенький в VB и почти ни какого опыта программирования в этой...

При любом изменении содержимого richTextBox выполнять определенный код
Здравствуйте. Как на с# сделать так, что бы при любом действии (например, добавления символа в...

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

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


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru