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

Попробуйте найти ошибку в коде функции, взятой из библиотеки structopt:

static inline bool is_valid_number(const std::string &input) {
  if (is_binary_notation(input) ||
      is_hex_notation(input) ||
      is_octal_notation(input)) {
    return true;
  }
  if (input.empty()) {
    return false;
  }
  std::size_t i = 0, j = input.length() - 1;
  // Handling whitespaces
  while (i < input.length() && input[i] == ' ')
    i++;
  while (input[j] == ' ')
    j--;
  if (i > j)
    return false;
  // if string is of length 1 and the only
  // character is not a digit
  if (i == j && !(input[i] >= '0' && input[i] <= '9'))
    return false;
  // If the 1st char is not '+', '-', '.' or digit
  if (input[i] != '.' && input[i] != '+' && input[i] != '-' &&
      !(input[i] >= '0' && input[i] <= '9'))
    return false;
  // To check if a '.' or 'e' is found in given
  // string. We use this flag to make sure that
  // either of them appear only once.
  bool dot_or_exp = false;
  for (; i <= j; i++) {
    // If any of the char does not belong to
    // {digit, +, -, ., e}
    if (input[i] != 'e' && input[i] != '.' &&
        input[i] != '+' && input[i] != '-' &&
        !(input[i] >= '0' && input[i] <= '9'))
      return false;
    if (input[i] == '.') {
      // checks if the char 'e' has already
      // occurred before '.' If yes, return false;.
      if (dot_or_exp == true)
        return false;
      // If '.' is the last character.
      if (i + 1 > input.length())
        return false;
      // if '.' is not followed by a digit.
      if (!(input[i + 1] >= '0' && input[i + 1] <= '9'))
        return false;
    }
    else if (input[i] == 'e') {
      // set dot_or_exp = 1 when e is encountered.
      dot_or_exp = true;
      // if there is no digit before 'e'.
      if (!(input[i - 1] >= '0' && input[i - 1] <= '9'))
        return false;
      // If 'e' is the last Character
      if (i + 1 > input.length())
        return false;
      // if e is not followed either by
      // '+', '-' or a digit
      if (input[i + 1] != '+' && input[i + 1] != '-' &&
          (input[i + 1] >= '0' && input[i] <= '9'))
        return false;
    }
  }
  /* If the string skips all above cases, then
  it is numeric*/
  return true;
}

Чтобы сразу случайно не прочитать ответ, добавлю картинку.

Не знаю, нашли вы ошибку или нет. Даже если вы ее нашли, я уверен, вы согласитесь, что найти такую ​​опечатку непросто. Более того, вы знали, что в функции есть ошибка. Если бы вы не знали, было бы трудно заставить вас внимательно прочитать и проверить весь этот код.

В таких случаях статический анализатор кода отлично дополнит классический обзор кода. Анализатор не устает и тщательно проверит весь код. В результате анализатор PVS-Studio замечает аномалию в этой функции и выдает предупреждение:

V560 Часть условного выражения всегда ложна: input [i] ‹=‘ 9 ’. structopt.hpp 1870

Для тех, кто не заметил ошибку, дам пояснение. Вот основная часть:

else if (input[i] == 'e') {
  ....
  if (input[i + 1] != '+' && input[i + 1] != '-' &&
      (input[i + 1] >= '0' && input[i] <= '9'))
      return false;
}

Вышеупомянутое условие проверяет, что i-й элемент представляет собой букву «е». Соответственно, следующая проверка input [i] ‹=‘ 9 ’ не имеет смысла. Результат второй проверки всегда false, о чем и предупреждает инструмент статического анализа. Причина ошибки проста: человек поторопился и допустил опечатку, забыв написать +1.

На самом деле оказывается, что функция не проверяет правильность введенных чисел, как ожидалось. Правильная версия:

else if (input[i] == 'e') {
  ....
  if (input[i + 1] != '+' && input[i + 1] != '-' &&
      (input[i + 1] >= '0' && input[i + 1] <= '9'))
      return false;
}

Интересный факт. Эту ошибку можно рассматривать как своего рода эффект последней строки. Ошибка была сделана в последнем условии функции. К концу этого фрагмента внимание программистов ослабло, и они допустили эту еле заметную ошибку.

Если вам понравилась статья об эффекте последней строки, рекомендую прочитать и о других подобных идеях: 0–1–2, memset, сравнения.

Всем пока. Престижность тем, кто сам нашел ошибку.