Какова стратегия, если утверждение не удается - PullRequest
7 голосов
/ 29 октября 2010

Утверждение используется, чтобы проверить, выполнено ли условие (предусловие, постусловие, инварианты) и помочь программистам найти дыры во время фазы отладки.

Например,

void f(int *p)
{
  assert(p);
  p->do();
}

Мой вопроснужно ли нам предполагать, что условие не может быть выполнено в режиме разблокировки, и обрабатывать случай соответствующим образом?

void f(int *p)
{
  assert(p);

  if (p)
  {
    p->do();
  }
}

В конце концов, утверждение означает, что проверяемое им условие НИКОГДА не должно быть ложным.Но если, если мы не проверим это, и он потерпит неудачу, программа вылетает.Похоже на дилемму.Как вы, ребята, справляетесь с этим?

Ответы [ 8 ]

21 голосов
/ 29 октября 2010

Если утверждение не выполнено, программа должна аварийно завершить работу .

Неудачное утверждение означает, что программист допустил фундаментальную ошибку в своем понимании того, как возможно выполнение программы. Это помощь в целях развития, а не помощь в производстве. В производстве можно обрабатывать исключений , так как они "могут" возникнуть, тогда как утверждения не должны "никогда" потерпеть неудачу.

Если вы находитесь в лагере, который говорит: «О, но что, если утверждения потерпят неудачу в производстве? Мне нужно их поймать!» тогда вы упускаете суть. Спросите себя, в таком случае, почему вы просто не генерируете исключение (или иначе обрабатываете ошибку)?

Вообще говоря, assert - это , а не , просто сокращение для "если условие не выполнено, выбросить исключение" (ну, иногда это операционная семантика, но это не денотационная семантика) , Скорее, ошибка утверждения означает, что приложение находится в состоянии, в которое разработчик не верит, даже возможно . Вы действительно хотите, чтобы код продолжал выполняться в таком случае? Ясно (я бы сказал), Нет .

2 голосов
/ 29 октября 2010

Защитное программирование всегда лучше.Вы всегда должны предполагать, что, несмотря на все ваши испытания, ваше приложение будет поставляться с ошибками.Поэтому в ваших интересах добавить проверки NULL в ситуациях, когда вы можете избежать обращения к указателю NULL и просто двигаться дальше.

Однако существуют ситуации, когда просто не существует простого способа избежать сбоя.и в этих случаях утверждение является вашим единственным способом обнаружения проблемы во время цикла разработки.

Однако один важный момент - утверждения также часто используются для выявления серьезных проблем с целостностью ваших данных.Если вы продолжите мимо этих утверждений, вы рискуете испортить данные.В этих случаях может быть лучше потерпеть крах, чем уничтожить ваши данные.(Очевидно, что любой тип обработчика сбоев, который хотя бы вызывает разумный пользовательский интерфейс с описанием ошибки, был бы предпочтительным).

1 голос
/ 29 октября 2010

Строго говоря, второй код имеет избыточность.

void f(int *p)
{
  assert(p);
  if (p)    // Beats the purpose of assertion
  {
    p->do();
  }
}

Утверждение означает, что произошла ошибка. Нечто неожиданное / необработанное. В приведенном выше коде либо

1) Вы правильно обрабатываете случай, когда p равно нулю. (не вызывая p-> do ()) - что предположительно является правильным / ожидаемым действием. Однако тогда утверждение является ложной тревогой .

2) С другой стороны, если, не вызывая p-> do (), что-то пойдет не так (возможно, далее в коде или в выводе), тогда утверждение верно, но не должно быть никакого смысла в продолжая в любом случае.

В приведенном выше коде программист работает очень усердно, чтобы обрабатывать случаи, которые в любом случае ошибочны.

Тем не менее, некоторые люди любят рассматривать утверждения как что-то пошло не так, но давайте посмотрим, получим ли мы по-прежнему правильный вывод . ИМО, это плохая стратегия и создает путаницу во время исправления ошибок.

0 голосов
/ 29 октября 2010

Поскольку многие люди комментируют перевод утверждений в режим выпуска:

В том, над чем я работаю, эффективность очень важна (иногда выполнение на больших наборах данных занимает от десятков часов до нескольких дней). Следовательно, у нас есть специальные макросы, которые утверждаются только в отладочном коде (запускаются во время QA и т. Д.). Например, assert внутри цикла for определенно является накладным расходом, и вы можете избежать этого в коде релиза. В конце концов, если все хорошо, утверждения не должны потерпеть неудачу.

Один из примеров, когда утверждения кода выпуска хороши, - если логика вообще не предназначена для попадания в определенную ветвь кода. В этом случае assert (0) - это хорошо [поэтому любой код assert (0) всегда можно оставить в коде выпуска].

0 голосов
/ 29 октября 2010

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

Не прилагайте больших усилий при обработке исключений. Просто убедитесь, что вы можете получить полное исключение, включая трассировку стека. Это относится, в частности, к сборке релиза.

0 голосов
/ 29 октября 2010

Утверждения полезны для отладки, как вы упомянули. Они никогда не должны превращать это в производственный код (как скомпилировано, конечно, можно обернуть их в #ifdefs)

Если у вас возникла проблема, когда вы не можете ее исправить, и вам нужна проверка в рабочем коде, я бы сделал что-то вроде:

void f(int *p)
{

  if (!p)
  {
    do_error("FATAL, P is null.");
  }

  p->do();
}

Где do_error - это функция, которая регистрирует ошибку и корректно завершает работу.

0 голосов
/ 29 октября 2010

Утверждения используются для выявления ошибок в тестировании. Теория заключается в том, что вы достаточно хорошо протестировали, чтобы знать, что это сработает, как только вы его выпустите.

Если есть вероятность того, что условие может возникнуть в реальной работе, не полагайтесь на утверждения - используйте исключения или какой-либо другой механизм ошибок.

0 голосов
/ 29 октября 2010

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...