>
>
>
V1105. Suspicious string modification u…


V1105. Suspicious string modification using the 'operator+='. The right operand is implicitly converted to a character type.

Анализатор обнаружил подозрительный код: строковая переменная типа 'std::basic_string' модифицируется с помощью оператора '+='. При этом правым операндом является выражение арифметического типа. Из-за неявных преобразований, проходимых перед вызовом оператора, может быть получен неожиданный результат.

Рассмотрим пример:

void foo()
{
  std::string str;
  str += 1000;     // N1
  str += ' ';
  str += 4.5;      // N2
  str += ' ';
  str += 400.52;   // N3
}

Разработчик хотел сформировать строку, состоящую из трёх чисел. Однако в результате исполнения этого кода получится следующее:

  • В строке N1 произойдёт неявное преобразование из типа 'int' в 'char'. Результат такого преобразования зависит от знаковости типа 'char' и версии стандарта C++. Например, один из возможных вариантов — константа '1000' сконвертируется в значение '-24', что соответствует символу из расширенной ASCII таблицы.
  • В строке N2 произойдёт неявное преобразование из типа 'double' в 'char'. Сначала будет отброшена дробная часть числа '4.5'. Поскольку полученное значение '4' умещается в диапазоне значений типа 'char', то в результате конверсии будет получен символ с ASCII кодом 4, который является непечатаемым символом.
  • В строке N3 содержится неопределённое поведение. После отбрасывания дробной части числа '400.52' результат не умещается в диапазоне значений типа 'char' (даже в случае, если он беззнаковый).

Примечание. Обратите внимание, хоть оба значения — 1000 и 400.52 — не помещаются в 'char', последствия будут разными. В случае 1000 мы имеем дело с сужающим преобразованием. Такой код компилируется, однако может быть некорректен. В свою очередь, преобразование числа с плавающей точкой — 400.52 к типу 'char', согласно стандарту языка, является неопределённым поведением.

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

void foo()
{
  std::string str;
  str += std::to_string(1000);
  str += ' ';
  str += std::to_string(4.5);
  str += ' ';
  str += std::to_string(400.52);
}

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

void foo()
{
  std::string str;

  // first option
  str += '*';

  // second option
  str += '\x2A';
}

Диагностическое правило выдаёт срабатывание:

  • достоверности уровня High, когда правый операнд вещественного типа;
  • достоверности уровня Medium, когда правый операнд целого типа в результате неявного преобразования будет усечён;
  • достоверности уровня Low, когда правый операнд целого типа в результате неявного преобразования останется с тем же значением и лежит в диапазоне [0 .. 127] (символы из нерасширенной таблицы ASCII).