![]() |
Модераторы: bsa |
![]() ![]() ![]() |
|
Proger10 |
|
||||
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 312 Регистрация: 16.12.2008 Репутация: нет Всего: нет |
Задумался о таком вопросе. Прерывать функцию можно как-то так:
Ну что-то в таком духе. Мне интересно - насколько часто такое используется и насколько это хороший тон программирования? Загуглил, но ничего внятного на эту тему не получил. Почему спрашиваю - во времена Бейсика были такие операторы, как GoTo (goto) или путаю с Паскалем...) ну не суть важно, в Паскале метки были и выборочно тоже из кода можно было перепрыгнуть на какую-либо метку в любую точку программы. Это считалось очень нехорошим тоном, поскольку могло сильно запутывать программиста, да и сильно снижать читабельность кода в целом. Хочу спросить относительно вот таких return'ов. Какое у Вас отношение к такому коду? В данном случае:
прошлый подход помогает избежать создания дополнительной переменной и соответственно выделения под неё памяти, пускай да и немного ![]() |
||||
|
|||||
Dem_max |
|
|||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1780 Регистрация: 12.4.2007 Репутация: 4 Всего: 39 |
Не парься Microsoft не гнушается использовать goto в функциях, так в некоторых моментах это самый наилучший и самый простой вариант.
-------------------- Американские программисты долго не могли понять, почему русские при зависании Windоws всё время повторяют "Твой зайка написал" ("Yоur bunnу wrоte") |
|||
|
||||
Arantir |
|
|||
Рыбак без удочки ![]() ![]() Профиль Группа: Участник Сообщений: 960 Регистрация: 18.11.2012 Репутация: нет Всего: 55 |
Если принять во внимание, что функция по идее своей не должна содержать столько уж дофига кода, чтобы return посередине делал ее намного быстрее (даже не смотря на то, что в оставшейся части кода ничего полезного не сделается), то return-ать через каждые пару строчек не очень хорошо.
Это действительно может сбить с толку тем, что выполнение до некоторых строчек вообще не дойдет при некоторых обстоятельствах. На самом деле удобство кода — довольно важная часть разработки в наше время. Проекты не делаются на один раз, они еще долго поддерживаются и развиваются. Так что удобный код нужен для этого развития. Если подумать, то и ООП заставляет компьютер делать много лишней работы, но его удобство все же перевешивает. Пару лишних if-ов погоды не сделают, разве что только пару тысяч раз в секунду эту функцию вызывать. Впрочем, в 10-20-и строчках return-ы не заметить довольно трудно. Так что это дело вкуса. return тоже о чем-то говорит, например о том, что тут функция обязана прекратится в любом случае. Это может быть таким себе семантическим намеком. Это сообщение отредактировал(а) Arantir - 9.6.2013, 05:31 -------------------- interface Жопа { // ATTENTION: has to be implemented by every class of the project for proper project work } |
|||
|
||||
maxim1000 |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Участник Сообщений: 3334 Регистрация: 11.1.2003 Где: Киев Репутация: 1 Всего: 110 |
В C действительно лучше, чтобы был один return. Дело в том, что как бы ни завершалась функция, нужно освобождать ресурсы (файлы закрывать, память освобождать, и т.п.). Писать это возле каждого return'а напряжно и вероятность забыть высокая.
В C++ к освобождению ресурсов другой подход (этим занимаются деструкторы), поэтому иметь несколько return'ов вполне нормально. Если в каком-то месте уже понятно, что вернуть и больше ничего не нужно делать, лучше написать return. Если писать что-то goto-образное или добавлять флажки и if'ы, только читабельность уменьшиться. Пример:
Здесь код показывает, что проверка на отрицательность к алгоритму отношения почти не имеет - просто проверка допустимых значений. Был бы это большой if (большой, потому что в самом алгоритме парой строк уже не обойтись), проследить логику было бы сложнее. Добавлено через 4 минуты и 19 секунд да, кстати, по поводу скорости и памяти: 1. скорость отличаться будет в пределах погрешности 2. память - очень сильно рекомендую забыть об экономии памяти на стеке, если речь идёт об отдельных значениях типа bool - она всё равно освободиться по выходу, так что остальной программе ни холодно, ни жарко от этой "экономии", конечно больших вещей туда пихать не нужно (массив на миллион лучше всё-таки в кучу), но про маленькие не стоит париться -------------------- qqq |
|||
|
||||
Alexeis |
|
|||
![]() Амеба ![]() Профиль Группа: Админ Сообщений: 11743 Регистрация: 12.10.2005 Где: Зеленоград Репутация: 4 Всего: 459 |
Я у себя практикую такую манеру (где есть необходимость в сильном ветвлении). Оборачиваю всю логику в try / catch . Правильный ход событий делается линейным без ветвлений и он тянется до конца try блока, в случае чего-то нештатного, я бросаю исключение типа const wchar_t* с текстом ошибки. В catch блоке делаются действия специфичные для любых ошибок и для этой в частности (если нужно что-то специально делать). Результат сохраняется в временной переменной и после после catch блока делаются операции, которые нужно произвести как для состояния ошибки так и для успеха, после чего возвращается результат работы. Получается одна точка выхода. Если ничего освобождать не нужно специально, то делаются 2е точки выхода - одна для успеха, другая для ошибки.
Этот ответ добавлен с нового Винграда - http://vingrad.com |
|||
|
||||
NoviceF |
|
||||
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 313 Регистрация: 13.3.2012 Где: Ростов-на-Дону Репутация: 2 Всего: 2 |
Тут 2 немного разные темы затронуты - false в середине функции - это сигнализирование об ошибке, вполне нормальное поведение. В зависимости от серзьёности ошибки можно рассмотреть возможность вместо возврата false кинуть исключение. А вот ветвление и возврат true, это другая ситуация. Не знаю, может это какой-то стереотип, но на мой взгляд такой подход более естественнен для возврата булевых значений:
Хотя, конечно, могут быть и обратные ситуации.. Например функция при удачном выполнении возвращает инициализированный объект, а при не удаче - сконструированный конструктором по умолчанию
Пример, естественно, надуманный, но принцип поясняет. В общем, зависит от контекста ![]() Ну и за утекающими ресурсами нужно следить - использовать для них управляющие объекты. |
||||
|
|||||
Dem_max |
|
|||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1780 Регистрация: 12.4.2007 Репутация: 4 Всего: 39 |
Угу для этого GOTO в определенное место, а там уже освободить ресурсы и сделать RETURN -------------------- Американские программисты долго не могли понять, почему русские при зависании Windоws всё время повторяют "Твой зайка написал" ("Yоur bunnу wrоte") |
|||
|
||||
Alexeis |
|
||||
![]() Амеба ![]() Профиль Группа: Админ Сообщений: 11743 Регистрация: 12.10.2005 Где: Зеленоград Репутация: 4 Всего: 459 |
Речь именно о ветвлении с целью проверки на состоянии ошибки. Например для избежания такого ветвления.
По моему, исключения шикарный механизм заменяющий goto в ситуациях когда нужно отработать неуспех функции.
Ресурсы это не всегда память. Будешь для каждого типа писать управляющие объекты? Кроме того, на освобождении бывает замешана синхронизация потоков. -------------------- Vit вечная память. Обсуждение действий администрации форума производятся только в этом форуме гениальность идеи состоит в том, что ее невозможно придумать |
||||
|
|||||
maxim1000 |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Участник Сообщений: 3334 Регистрация: 11.1.2003 Где: Киев Репутация: 1 Всего: 110 |
да, и это нормально для памяти и файлов уже есть для остальных написать несложно, если совсем лениво - можно написать объект вроде on_exit, которому в конструкторе передаётся функтор, который будет вызван при выходе из области видимости любое разнесение логики выделения и освобождения ресурса в программе увеличивает вероятность: 1. забывания его освободить 2. неучтения случаев, когда его нужно освободить если же есть управляющий объект, программисту не нужно думать "а что мне надо очистить при выходе?", "а что будет, если вдруг возникнет исключение?", и т.п. -------------------- qqq |
|||
|
||||
NoviceF |
|
|||
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 313 Регистрация: 13.3.2012 Где: Ростов-на-Дону Репутация: 2 Всего: 2 |
По-моему, исключения довольно тяжеловесны и их стоит использовать именно для "Исключительных ситуаций". Использовать их как замену ветвлению по умолчанию, довольно расточительно. Но не исключаю ситуации, когда это может быть оправдано. Писать (а лучше использовать готовые) управляющие объекты это C++ путь, использовать ручное управление ресурсами - C путь. Вообще я бы посмотрел примеры, где использовать управляющие объекты это плохо, и лучше (надёжнее) обойтись без них. |
|||
|
||||
bsa |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Модератор Сообщений: 9185 Регистрация: 6.4.2006 Где: Москва, Россия Репутация: 85 Всего: 196 |
С точки зрения производительности проблем тоже нет. Так как компилятор банально ставит операцию перехода на конец функции (бывают исключения), таким образом она завершается штатно. Если посмотреть исходники драйверов ядра Linux, написанные на С, то там будет полно операторов goto. Потому что ресурсы в ядре необходимо очень четко контролировать, а сделать это через вложенные условные блоки не всегда получается. |
|||
|
||||
math64 |
|
|||
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 2505 Регистрация: 12.4.2007 Репутация: 12 Всего: 72 |
Операторы return, goto, continue, break (кроме switch) - мешают рефакторингу. В некоторых IDE можно выделить кусок кода и выделить его в функцию.
А так в них ничего плохого нет - даже полученные ресурсы будут освобождены автоматически (если они освобождаются в деструкторах локальных переменных) |
|||
|
||||
Alexeis |
|
|||
![]() Амеба ![]() Профиль Группа: Админ Сообщений: 11743 Регистрация: 12.10.2005 Где: Зеленоград Репутация: 4 Всего: 459 |
Объект имеет смысл писать если ситуация повторяется. И кроме того, говорю ж, частенько последовательность уничтожения имеет значение. В C# для таких вещей даже придумали финализаторы. Память памятью, а ресурс ресурсом. Или ты объекты синхронизации тоже будешь сигнализировать деструкторами? Такая же история с асинхронной работой. Например с прерываниями. Одна операция может быть разделена на цепочку вызовов. Фактически ресурс захваченный в первом прерывании может быть освобожден в 3м. Т.е. не должен уничтожаться при выходе за границу блока.
Ну если в системе 64кб памяти, то исключения лучше не использовать, как и многие другие механизмы С++ . При наличии хотя бы 1Мб, это позволительно. -------------------- Vit вечная память. Обсуждение действий администрации форума производятся только в этом форуме гениальность идеи состоит в том, что ее невозможно придумать |
|||
|
||||
maxim1000 |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Участник Сообщений: 3334 Регистрация: 11.1.2003 Где: Киев Репутация: 1 Всего: 110 |
Как правило "последний захвачен - первый освобождён" покрывает процентов 90 случаев. Для всех остальных вариантов можно использовать динамическое время жизни (например, unique_ptr с его reset). Главное, чтобы в каждом месте программы было очевидно, кто какой объект удаляет. Эту ответственность можно передавать (всё тем же unique_ptr), но если использовать голые указатели, то рано или поздно начнутся утечки. Касательно объектов синхронизации - только в конструкторах и деструкторах. Если логика их выделения более сложная, будут дедлоки, ибо люди несовершенны. А одна из популярных техник по избежанию дедлоков - иерархический захват мьютексов, который, по сути, и моделируется "последним захвачен - первым освобождён". Про финализаторы уверенно говорить не могу, но если не ошибаюсь, порядок их вызова недетерминирован, более того, нельзя рассчитывать, что он будет вызван (по крайней мере, в обозримом будущем). Но тут могу ошибаться. Это сообщение отредактировал(а) maxim1000 - 10.6.2013, 18:17 -------------------- qqq |
|||
|
||||
Alexeis |
|
|||
![]() Амеба ![]() Профиль Группа: Админ Сообщений: 11743 Регистрация: 12.10.2005 Где: Зеленоград Репутация: 4 Всего: 459 |
Т.е. ты предлагаешь порядок уничтожения задавать при помощи строго заданного порядка определения объектов-переменных в блоке? Если они не вызываются явно то так, но это аварийный случай, но вообще их придумали, чтобы задавать явно порядок освобождения, поскольку gc будет удалять в произвольном порядке.
Так это требует явного указания. Сам компилятор не освободит мьютекс. Он ведь существует долго, а захватывается и освобождается часто. -------------------- Vit вечная память. Обсуждение действий администрации форума производятся только в этом форуме гениальность идеи состоит в том, что ее невозможно придумать |
|||
|
||||
![]() ![]() ![]() |
Правила форума "C/C++: Для новичков" | |
|
Запрещается! 1. Публиковать ссылки на вскрытые компоненты 2. Обсуждать взлом компонентов и делиться вскрытыми компонентами
Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, JackYF, bsa. |
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей) | |
0 Пользователей: | |
« Предыдущая тема | C/C++: Для новичков | Следующая тема » |
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |