В процедурных языках, где функции являются ключевыми игроками, парадигма проектирования по контракту в основном гласит, что существует соглашение между функцией, которая принимает параметры, и вызывающей стороной.
Соглашение звучит примерно так: «если вызывающая сторона обеспечивает выполнение предварительных условий функции, то функция будет вести себя ожидаемым образом и / или возвращать ожидаемые значения».
Если мы пишем код строго таким образом, то только вызывающая сторона отвечает за обеспечение правильного ввода в функции. Но во имя защитного программирования представляется целесообразным включить внутренние меры предосторожности на случай, если вызывающая сторона сделает что-то глупое.
Что касается наилучшего подхода к архитектуре и дизайну программного обеспечения?
Это ответственность звонящего. Например, что может быть реализация strlen
делать, если передан нулевой указатель? Единственное, что он может сделать, — это прервать программу — что является жизнеспособным, хотя и радикальным вариантом в C. В C ++ он может вызвать исключение (но не в том случае, если он соответствует стандарту C ++), но работа с этим исключением будет очень сложно. Таким образом, единственное разумное решение, которое позволяет программе продолжать работать в известном состоянии, это для strlen
не вызываться с нулевым указателем в качестве параметра, что возлагает ответственность за проверку этого на вызывающий код.
Как говорил Нил, проверка является обязанностью звонящего. Вы сказали,
кажется разумным включить внутренние меры предосторожности на случай, если вызывающий абонент сделает что-то глупое.
Чтобы описать, почему это не идеальный подход, я остановлюсь на примере Нейла, который использовал проверку на нулевые указатели, передаваемые strlen
Представьте себе два сценария:
strlen
проверяет ввод заранее.strlen
проверяет свои аргументы внутри, прежде чем оперировать ими. Нет никакой разницы в эффективности между этими двумя методами, если вы делаете один вызов strlen
, Тем не менее, представьте, что вместо одного звонка strlen
, ты звонишь strlen
, strstr
и другие строковые функции несколько раз подряд. В сценарии 1, независимо от того, выполняете ли вы 1, 2, 10 или 100 вызовов функций из строковой библиотеки, вам нужно проверять только неправильные входные данные один раз. В сценарии 2 каждый вызов вынужден проверять ввод, что значительно замедляет процесс.