Это действительно сводится к этому вопросу: что вы имеете в виду , когда произносите слово «предварительное условие»?
То, как вы, кажется, используете это слово, означает «а»вещь, которая проверяется при вызове этой функции. "То, как Херб, стандарт C ++ и, следовательно, система контрактов C ++, означают, что это «вещь, которая должна быть верной для правильного выполнения этой функции, и если она не верна, то вы сделали неправильную вещь и мир разрушен . "
И эта точка зрения действительно сводится к тому, что означает" контракт ".Рассмотрим vector::operator[]
против vector::at()
.at
не имеет предварительного условия в стандарте C ++;выдает, если индекс выходит за пределы допустимого диапазона.Это значит, что часть интерфейса из at
позволяет передавать его вне допустимых значений, и он будет реагировать ожидаемым, предсказуемым образом.
дело не в operator[]
.Это , а не часть интерфейса этой функции, которую вы можете передавать за пределы диапазона индексов.Таким образом, у него есть предварительное условие, что индекс не выходит за пределы допустимого диапазона.Если вы передадите ему индекс вне допустимого диапазона, вы получите неопределенное поведение .
Итак, давайте рассмотрим несколько упрощенных примеров.Я собираюсь построить vector
и затем прочитать целое число от пользователя, а затем использовать его для доступа к vector
, который я построил тремя различными способами:
int main()
{
std::vector<int> ivec = {10, 209, 184, 96};
int ix;
std::cin >> ix;
//case 1:
try
{
std::cout << ivec.at(ix);
}
catch(const std::exception &)
{
std::cout << "Invalid input!\n";
}
//case 2:
if(0 <= ix && ix < ivec.size())
std::cout << ivec[ix];
else
std::cout << "Invalid Input!\n";
//case 3:
std::cout << ivec[ix];
return 0;
}
В случае 1, мы видимиспользование at
.В случае неправильного ввода мы отлавливаем исключение и обрабатываем его.
В случае 2 мы видим использование operator[]
.Мы проверяем, находится ли ввод в допустимом диапазоне, и, если это так, вызывают operator[]
.
В случае 3 мы видим ... ошибку в нашем коде .Зачем?Потому что никто не продезинфицировал ввод.Кто-то должен был, и предварительное условие operator[]
говорит, что это работа вызывающего абонента.Вызывающая сторона не может очистить свои входные данные и, таким образом, представляет неработающий код.
Вот что означает заключение контракта: если код нарушает контракт, то ошибка кода заключается в его нарушении.
Но, как мы видим, контракт, по-видимому, является фундаментальной частью интерфейса функции.Если так, то почему эта часть интерфейса находится в тексте стандарта, а не в видимом объявлении функции, где люди могут его видеть?Это право - весь смысл языковой функции контрактов: позволить пользователям выражать этот специфический вид языка в языке.
Подводя итог, контракты предположений , которые кусок кода делает о состоянии мира.Если это предположение неверно, то оно представляет состояние мира, которое не должно существовать, и, следовательно, ваша программа содержит ошибку.Это идея, лежащая в основе дизайна возможностей контрактного языка.Если ваш код это проверяет, это не то, что вы предполагаете, и вы не должны использовать предварительные условия для его определения.
Если это условие ошибки, то вам следует использовать предпочитаемый механизм ошибок, а не контракт.