| Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
| Форум программистов > C/C++: Общие вопросы > Где лучше выполнять проверку корректности исходных |
| Автор: Нитонисе 23.5.2013, 16:51 |
| Есть класс, данными которого являются в том числе численные значения. Например есть некий параметр Х, который может принимать значения от 0 до 1. Есть некоторая функция, которая задает этот параметр, например SetX(double x). Всякий раз в подобных случаях я ломаю голову - где лучше проверять корректность данных - внутри функции SetX или же на стадии подготовки данных для этой функции, в данном случае это аргумент x. Казалось бы удобнее это делать вне класса, но иногда кажется что и внутри класса это уместно. Ведь если функцию SetX этим механизмом проверки корректности аргумента не снабдить, то можно ненароком этому параметру присвоить какое-то некорректное значение. |
| Автор: baldina 23.5.2013, 16:56 |
| внутри. так будет проверено каждое обращение функции. и вне - так будет проверено значение, введенное пользователем, что даст возможность не отвалиться по исключению, возбужденному в SetX(), а повторно выполнить ввод. Добавлено через 1 минуту и 57 секунд во втором случае проверка должна быть не перед вызовом SetX(), а после получения значения. если это значение не ввод пользователя, а вычисленный результат, проверять его нужно, видимо, в точке принятия решения - передавать его дальше или нет, т.е. зависит от конкретного приложения. |
| Автор: Нитонисе 23.5.2013, 17:01 |
| Если проверять аргумент х и на стадии его формирования и внутри функции - то это будет дублирование проверки. Разумно ли это? |
| Автор: bsa 23.5.2013, 17:46 |
| внутри функции параметры проверяются на корректность для данной функции. А вне функции они проверяются на допустимость для данного алгоритма. |
| Автор: Нитонисе 23.5.2013, 18:16 |
| То есть если для некоторых вычислений, где используется этот параметр Х должен принимать значения от 0 до 1, то при выполнении функции SetX(double x) проверку аргумента надо производить перед вызовом функции? А в самой функции тогда остается просто SetX(double x){this->X = x}; |
| Автор: NoviceF 23.5.2013, 19:13 |
| Считаю внутри функции нужно проводить в любом случае.. Сегодня ты проверяешь результаты снаружи, а завтра кто-то воспользуется твоим классом и начнёт туда записывать непонятно что. Класс должен сопротивляться при помощи ассертов, возвратов фолсов и выбрасывания исключений |
| Автор: NoviceF 23.5.2013, 19:20 | ||
Если для класса this->X имеет смысл только при положительных значениях или в определённом диапазоне - это и нужно бы проверить, перед выполнением присваивания this->X = x. Вообще, если значимы только 0 или не ноль, логичнее было бы bool использовать. Добавлено через 1 минуту и 3 секунды Корректность работы намного предпочтительнее производительности в большинстве случаев. Добавлено через 12 минут и 22 секунды Когда функция одна, может и не совсем виден масштаб проблемы.. А если 4-5 функций последовательно вызывают друг друга и на пятой приложение падает.. а в процессе отладки выясняется, что проблема в аргументах переданных первой функции второй. По плану первая функция должна была всё правильно расчитать, но где-то закралась ошибка и результат её работы не может быть корректно обработан второй функцией.. И если во второй функции (и всех последующих) не делать проверку агрументов - ошибка лавиной пройдёт через весь маршрут. Ну, и если нет предположений о причине ошибки (а обычно у меня их нет |
| Автор: borisbn 24.5.2013, 05:49 |
| Есть такое правило - если ф-ция public, то она должна проверять параметры, если private - нет. Ессно, это - не догма, но я пользуюсь и мне так удобно |
| Автор: NoviceF 24.5.2013, 09:06 |
| На мой взгляд, даже в приватных функциях, как минимум ассерты не повредят |
| Автор: bsa 24.5.2013, 15:49 |
Смотри, квадратный корень можно брать от любого неотрицательного числа. Поэтому функция извлечения корня проверяет параметр на отрицательность. Если он отрицательный, то тогда выдает ошибку. Твой алгоритм считает сложную функцию. И на каком-то этапе перед извлечением корня ты проверяешь промежуточный результат (по идее, правильно проверять только входные параметры, но иногда для проверки необходимо проделать половину всех вычислений) на корректность. И не обязательно на неотрицательность. Вот именно это я и имел в виду. Смысл проверять перед функцией имеется только тогда, когда функция не может сигнализировать об ошибке. |
| Автор: Нитонисе 24.5.2013, 16:09 | ||
Да, именно. И мне кажется рациональнее проверять именно перед функцией, а не внутри нее. Одна из причин - если проверять внутри функции, то нужно разрабатывать систему сигнализирования о том что именно функции не понравилось. Например аргумент должен быть положительным и не больше единицы. Значит функция своим возвращаемым значением должна уметь сказать - "работа не сделана, аргумент отрицательный" или "работа не сделана, аргумент больше единицы". По идее этим возвращаемым из ункции значением может быть простой int. Например если вернули 1 - функция сработала как надо, вернули 2 - получили отрицательный аргумент и поэтому не обработали, вернули 3 - получили аргумент больше единицы и поэтому не обработали. Мне кажется такой подход чересчур громоздкий. Он может быть оправдан только если разрабатываемый класс будут использовать сторонние разработчики, которые могут и не знать какие проверки надо выполнять перед выполнением функции. Поэтому для них все проверки можно сразу в функцию зашить. А если только я использую этот класс и четко понимаю как надо его использовать, то такая внутренняя проверка может и не нужна. |
| Автор: NoviceF 24.5.2013, 16:29 | ||||||
Если только ты используешь, чем плох
? На дебаге тебе же самому будет полезно сразу видеть где ошибка, вместо того, чтобы лишний раз расставлять printf() или лезть в отладчик, а в релизе этой проверки просто не будет, так что на быстродействии функции в конечном итоге эта проверка вообще не отразится и никакой двойной работы небудет. Добавлено через 6 минут и 37 секунд
Не обязательно.. В большинстве случаев вполне можно зарезервировать какое-нибудь значение для ошибки (например возвращать объект, сконструированные дефолтным конструктром, вместо инициализированного (наверно не очень эффективно, но как вариант), а если из-за данной ошибки программа не должна выполняться дальше или нужно её обрабатывать специальным образом - можно кинуть исключение. У меня вообще нет никакой принципиальной позиции в этом вопросе, но небольшой практический опыт говорит, что лучше проверять.. |
| Автор: Нитонисе 24.5.2013, 17:07 | ||
Я пишу программы в Builder XE. Там при запуске программы в отладочном режиме, если происходит сбой, место в программе где произошел сбой выявляется автоматически. Так что если бы вдруг затупила эта функция, то отладчик бы на нее и указал. То есть это как сигнал для меня, что при передаче аргумента в эту функцию я не все внештатные ситуации обработал. |
| Автор: baldina 24.5.2013, 18:15 |
| независимо от того, в чем ты пишешь, ошибка произойдет не в месте assert, а когда все протухнет. это может оказаться совсем другая функция. в каких-то случаях приложение не обрушится, просто будет работать криво. и ты будешь бегать с бубном в отладчике |
| Автор: kamre 25.5.2013, 03:53 | ||
Можно еще воспользоваться системой типов и ввести для таких значений свой тип данных с соответствующим инвариантом. При этом любой экземпляр класса гарантирует инвариант, а функция просто принимает на вход этот тип данных и ничего не проверяет. |