﻿# Проверяем исходный код WPF Samples от Microsoft

С целью популяризации анализатора кода PVS\-Studio, который научился проверять помимо C\+\+, ещё и C\# проекты, мы решили проверить исходный код WPF примеров, предлагаемых компанией Microsoft\.

![0407_Microsoft_WPF_Samples_ru/image1.png](https://import.viva64.com/docx/blog/0407_Microsoft_WPF_Samples_ru/image1.png)

С выходом Windows Vista, была представлена новая система для построения красивых клиентских приложений \- Windows Presentation Foundation \(WPF\)\. Данная графическая подсистема включена в состав \.NET Framework начиная с версии 3\.0\. Она использует язык разметки XAML и пришла на смену устаревшему WinForms\. На мой взгляд, основным недостатком WinForms было то, что он осуществлял всю прорисовку на центральном процессоре\. WPF поступала более логически и отдавала прорисовку своих компонентов DirectX\. Сейчас WPF практически вытеснило WinForms и позволяет делать универсальные интерфейсы сразу для трех платформ \(PC, XBOXOne, Winphone\)\.

Для анализа исходных кодов WPF примеров от Microsoft \([исходники примеров](https://github.com/Microsoft/WPF-Samples)\) был использован статический анализатор кода [PVS\-Studio](https://pvs-studio.ru/ru/pvs-studio/download/) версии 6\.05\.

Интересной особенностью рассматриваемого Solution является то, что наряду с C\# проектами там содержатся проекты, написанные на С\+\+\.  Об этой особенности я узнал только из списка ошибок, найденных PVS\-Studio\. Плагин PVS\-Studio для Visual Studio без каких\-либо дополнительных манипуляций от пользователя проанализировал и вывел в сообщения, относящиеся как к C\#, так и к С\+\+ коду\.

![0407_Microsoft_WPF_Samples_ru/image3.png](https://import.viva64.com/docx/blog/0407_Microsoft_WPF_Samples_ru/image3.png)

Рисунок 1\. В окне PVS\-Studio одновременно отображаются предупреждения, относящиеся как к C\#, так и C\+\+ коду проверенного проекта \(нажмите на рисунок для увеличения\)\.

## C\# Ошибки

**1\. Ошибки при составлении условий инструкции if**

Ошибки при сравнении чего\-либо с чем\-либо \- весьма распространённая проблема у программистов\. Давайте пройдемся по ним\. 

В данном исходном коде присутствует два абсолютно одинаковых условия: 

```cpp
public int Compare(GlyphRun a, GlyphRun b)
{
  ....
  if (aPoint.Y > bPoint.Y) // <=
  {
    return -1;
  }
  else if (aPoint.Y > bPoint.Y) // <=
  {
    result = 1;
  }
  else if (aPoint.X < bPoint.X)
  {
    result = -1;
  }
  else if (aPoint.X > bPoint.X)
  {
    result = 1;
  }
  ....
}
```

[V3003](https://pvs-studio.ru/ru/docs/warnings/v3003/) The use of 'if \(A\) \{\.\.\.\} else if \(A\) \{\.\.\.\}' pattern was detected\. There is a probability of logical error presence\. Check lines: 418, 422\. txtserializerwriter\.cs 418

Что именно они хотели сравнить во втором случае \- не совсем ясно, но явно не то, что написали\.

Мы поголовно пишем проверки на _null_ в условия, чем оберегаем программу от внештатных ситуаций\. Можно сказать, что большая часть условий _if_ состоит именно в проверках на _null_ каких\- либо полей или переменных\. Вместе с  тем,  иногда проверки бывают не только излишни, но и могут  таить в себе логическую ошибку:

```cpp
public static string FindNumeric(string content)
{
  string[] values = content.Split(' ');
  if (values != null)
  {
    return values[0];
  }
  return "none";
}
```

[V3022](https://pvs-studio.ru/ru/docs/warnings/v3022/) Expression 'values \!\= null' is always true\. Util\.cs 287

Можно предположить, что автор хотел проверить, что _values_ содержит больше 0 элементов, но я так и не смог придумать ситуации, когда _Split_ вернет пустой массив\. В любом случае, как ни крути, проверка на _null_ здесь была совершенно лишняя\.

Как я говорил, проект содержит код из С\+\+ и C\# диагностик\. У меня сложилось впечатление, что к следующему коду приложил руку именно C\+\+ программист\. 

```cpp
private void LoadNotes()
{
  var fs = new FileStream("NotesFile", FileMode.Open);
  if (fs != null)
  {
    ....
}
```

[V3022](https://pvs-studio.ru/ru/docs/warnings/v3022/) Expression 'fs \!\= null' is always true\. MainWindow\.cs 66

На самом деле, даже в C\+\+ коде такой вариант ошибочен, а в C\# так вообще "странно" смотрится\. Почему так неверно писать в C\+\+ коде, описано в статье "[Проверяем исходный код 7\-Zip с помощью PVS\-Studio](https://pvs-studio.ru/ru/blog/posts/cpp/0402/)", ну, а мы продолжим заниматься разбором C\# кода\.

Далеко от подобных ситуаций нам уйти не удалось\. В Solution нашлось две практически одинаковых функции \(спасибо "copy\-paste"\) с одной и той же ошибкой: 

```cpp
private void SerializeObjectTree(object objectTree)
{
  TextWriter writer = new StreamWriter(_stream);
  try
  {
    string fileContent =
     XamlRtfConverter.ConvertXamlToRtf(
         XamlWriter.Save(objectTree));
    writer.Write(fileContent);
  }
  finally
  {
    if (writer != null)
      writer.Close();
  }
}
```

[V3022](https://pvs-studio.ru/ru/docs/warnings/v3022/) Expression 'writer \!\= null' is always true\. htmlserializerwriter\.cs 324

Ну не будет _writer_ нулевой ссылкой\.\.\.

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

```cpp
protected Size SizeParser(string o)
{
  ....
  if (sizeString.Length == 0 || sizeString.Length != 2)
   throw new ApplicationException("Error: a size should 
           contain two double that seperated by a space 
           or ',' or ';'");
  ....
}
```

[V3023](https://pvs-studio.ru/ru/docs/warnings/v3023/) Consider inspecting the 'sizeString\.Length \=\= 0 \|\| sizeString\.Length \!\= 2' expression\. The expression is excessive or contains a misprint\. MainWindow\.cs 140

Судя по тексту ошибки, в данном случае, проверка на 0 излишняя, достаточно было проверить _sizeString\.Length_ на неравенство 2\.

В длинных телах инструкции _if_ очень сложно обнаружить бессмысленные проверки глазами\.

```cpp
private static void WriteElement(....)
{
  if (htmlWriter == null)
  {
    ....
  }
  else
  {
     if (htmlWriter != null && htmlElementName != null)
     {
       ....
  ....
}
```

[V3063](https://pvs-studio.ru/ru/docs/warnings/v3063/) A part of conditional expression is always true: htmlWriter \!\= null\. HtmlFromXamlConverter\.cs 491

Для анализатора это не проблема\. Кстати, благодаря любимому нашему копированию\-вставке, ошибка была найдена сразу в двух проектах: _HtmlToXamlDemo_ и _DocumentSerialization_\.

Конечно, бессмысленные проверки встречаются не только в длинных функциях, но и в пределах двух\-трех строчек\.

```cpp
private void OnFlipPicTimeline(object sender, EventArgs e)
{
  var clock = (Clock) sender;
  if (clock.CurrentState == ClockState.Active) // Begun case
  {
    return;
  }
  if (clock.CurrentState != ClockState.Active) // Ended case
  {
    ....
  }
}
```

[V3022](https://pvs-studio.ru/ru/docs/warnings/v3022/) Expression 'clock\.CurrentState \!\= ClockState\.Active' is always true\. MainWindow\.cs 103

В принципе, ничего страшного, но, когда после идет инструкция _if_ вложенная еще в один _if_ и еще и еще\.\.\. Хочется избавиться хотя бы от бессмысленных проверок для лучшего восприятия кода, который, на самом деле, читается гораздо чаше чем пишется\.

Давайте немного передохнём\. И посмотрим на вот такую необычную функцию, которая мне встретилась\. Тело функции приведено полностью:

```cpp
private void UpdateSavings()
{
  Savings = TotalIncome - (Rent + Misc + Food);
  if (Savings < 0)
  {
  }
  else if (Savings >= 0)
  {
  }
}
```

[V3022](https://pvs-studio.ru/ru/docs/warnings/v3022/) Expression 'Savings \>\= 0' is always true\. NetIncome\.cs 98

Также было найдено много \(более 60\) сравнений вещественных чисел \(_double_\) с конкретным 0\.

```cpp
if (leftConst != null && leftConst.Value == 0)
{
  // 0 + y;  return y;
  return newRight;
}
```

К примеру:

* V3024 An odd precise comparison: leftConst\.Value \=\= 0\. Consider using a comparison with defined precision: Math\.Abs\(A \- B\) < Epsilon\. AddExpression\.cs 34
* V3024 An odd precise comparison: leftConst\.Value \=\= 1\. Consider using a comparison with defined precision: Math\.Abs\(A \- B\) < Epsilon\. MultExpression\.cs 42
* V3024 An odd precise comparison: leftConst\.Value \=\= \-1\. Consider using a comparison with defined precision: Math\.Abs\(A \- B\) < Epsilon\. MultExpression\.cs 47 
* и так далее\.\.\.

Статьи не хватит все строчки привести\. Данное предупреждение у нас находится на 3\-м уровне, т\.к\. её актуальность сильно зависит от специфики программы\. В случае, если над числами производится математические вычисления \(манипуляциях со значением\), то не гарантируется, что мы получим конкретное число: \-1, 0, 1\. Отклонение в 0,00000000001уже приведет к неверному результату сравнения\. Однако,  если логика программы предполагает запись в вещественные числа \(_double_\) дискретных значений, то подобные проверки не являются ошибкой\.

**2\. Ошибки в инициализации и при присвоении переменных**

Функция \- отличная штука, которая не только позволяет убрать повторяющиеся код, но и упростить понимание участка кода, где эта функция используется\. Особенно важно, чтобы функция выполняла именно ту задачу, которая описана в её имени и сигнатуре вызова\. Но так бывает не всегда\. Возьмем, например, следующий участок кода\. Функция приведена полностью для лучшего понимания ситуации\.

```cpp
public bool OpenDocument(string fileName)
{
  Microsoft.Win32.OpenFileDialog dialog;
  // If there is a document currently open, close it.
  if (this.Document != null)  CloseFile();
  dialog = new Microsoft.Win32.OpenFileDialog();
  dialog.CheckFileExists = true;
  dialog.InitialDirectory = GetContentFolder();
  dialog.Filter = this.OpenFileFilter;
  bool result = (bool)dialog.ShowDialog(null);
  if (result == false)  return false;

  fileName = dialog.FileName; // <=
  return OpenFile(fileName);
}
```

[V3061](https://pvs-studio.ru/ru/docs/warnings/v3061/) Parameter 'fileName' is always rewritten in method body before being used\. ThumbViewer\.xaml\.cs 192

Имя файла, которое предполагается открыть, перетирается прямо перед его первым использованием _fileName \= dialog\.FileName_\. Да, в данном случае, откроется диалоговое окно и будет выбран файл пользователя, но зачем тогда нужен параметр, который по факту не используется?

Нехватка времени и копирование\-вставка иногда порождают весьма странные конструкции:

```cpp
public MailSettingsDialog()
{
  ....
  _timerClock = _timerClock = new DispatcherTimer(); 
  ....
}
```

[V3005](https://pvs-studio.ru/ru/docs/warnings/v3005/) The '\_timerClock' variable is assigned to itself\. MailSettingsDialog\.cs 56

Казалось бы, не самая страшная опечатка, но она наталкивает на мысль, а туда ли мы "пишем во второй раз"\. Ну, например, как здесь:

```cpp
private void DumpAllClipboardContentsInternal()
{ 
  ....
  if (dataObject == null)
  {
    clipboardInfo.Text =
      clipboardInfo.Text =
        "Can't access clipboard now! 
          \n\nPlease click Dump All Clipboard 
              Contents button again.";
  } 
  else 
  {
     ....
}
```

[V3005](https://pvs-studio.ru/ru/docs/warnings/v3005/) The 'clipboardInfo\.Text' variable is assigned to itself\. MainWindow\.cs 204

Вообще, код изобилует странными присваиваниями: 

```cpp
private void DoParse(string commandLine)
{
  ....
  strLeft = strRight = string.Empty;
  strLeft = strs[0];
  strRight = strs[1];
  ....
}
```

[V3008](https://pvs-studio.ru/ru/docs/warnings/v3008/) The 'strLeft' variable is assigned values twice successively\. Perhaps this is a mistake\. Check lines: 55, 54\. CommandLine\.cs 55

[V3008](https://pvs-studio.ru/ru/docs/warnings/v3008/) The 'strRight' variable is assigned values twice successively\. Perhaps this is a mistake\. Check lines: 56, 54\. CommandLine\.cs 56

_strLeft и strRight_ \- это просто локальные переменные типа _string_\.

Ну или вот, дальнейший пример кода, более некорректный\. В нем зачем\-то так много чего\-то считали, а после еще раз пересчитали и записали в туже переменную\.

```cpp
private object InvokMethod(....)
{
  arg = commandLine.Substring(
    commandLine.IndexOf("(", StringComparison.Ordinal) + 1,
      commandLine.IndexOf(")", 
        StringComparison.Ordinal) - 
        (commandLine.IndexOf("(", 
          StringComparison.Ordinal) + 1));
  arg = commandLine.Substring(
    commandLine.IndexOf("(", 
      StringComparison.Ordinal) + 1);
}
```

[V3008](https://pvs-studio.ru/ru/docs/warnings/v3008/) The 'arg' variable is assigned values twice successively\. Perhaps this is a mistake\. Check lines: 176, 173\. CommandLine\.cs 176

И еще много\-много таких или подобных примеров бессмысленного первичного присвоения:

```cpp
private void DrawFormattedText(DpiScale dpiInfo)
{
  ....
  Geometry geometry = new PathGeometry();
  geometry = formattedText.BuildGeometry(
     new System.Windows.Point(0, 0));
  ....
}
```

* V3008 The 't' variable is assigned values twice successively\. Perhaps this is a mistake\. Check lines: 141, 115\. TrackBall\.cs 141
* V3008 The 't' variable is assigned values twice successively\. Perhaps this is a mistake\. Check lines: 141, 115\. TrackBall\.cs 141
* V3008 The 'columnSpan' variable is assigned values twice successively\. Perhaps this is a mistake\. Check lines: 2115, 2101\. HtmlToXamlConverter\.cs 2115
* V3008 The '\_timerInterval' variable is assigned values twice successively\. Perhaps this is a mistake\. Check lines: 52, 47\. ClientForm\.cs 52
* V3008 The 'matrix1' variable is assigned values twice successively\. Perhaps this is a mistake\. Check lines: 126, 125\. MainWindow\.cs 126
* V3008 The 'matrixResult' variable is assigned values twice successively\. Perhaps this is a mistake\. Check lines: 140, 138\. MainWindow\.cs 140
* V3008 The 'matrixResult' variable is assigned values twice successively\. Perhaps this is a mistake\. Check lines: 351, 349\. MainWindow\.cs 351
* V3008 The 'matrixResult' variable is assigned values twice successively\. Perhaps this is a mistake\. Check lines: 369, 367\. MainWindow\.cs 369
* V3008 The 'pointResult' variable is assigned values twice successively\. Perhaps this is a mistake\. Check lines: 480, 478\. MainWindow\.cs 480
* V3008 The 'columnSpan' variable is assigned values twice successively\. Perhaps this is a mistake\. Check lines: 1930, 1917\. htmltoxamlconverter\.cs 1930
* V3008 The 'geometry' variable is assigned values twice successively\. Perhaps this is a mistake\. Check lines: 56, 55\. MainWindow\.xaml\.cs 56
* V3008 The 'pathGeometry' variable is assigned values twice successively\. Perhaps this is a mistake\. Check lines: 66, 65\. MainWindow\.xaml\.cs 66

Писать каждый пример смысла нет, тем более нас ожидает ещё много важных и серьезных ошибок\.

**3\. Пара разнородных ошибок**

Пробрасывая исключения, важно сохранить стек вызова, чтобы потом по логам понять \- "а что у пользователя в принципе\-то упало"\. Далеко не все знают, как правильно это делать\.

```cpp
public static object InvokePropertyOrMethod(....)
{
  try
  {
     ....
  }
  catch (MissingMethodException e)
  {
    ....
    throw e;
  }
  catch (AmbiguousMatchException e)
  {
     throw e;
  }
  return resultObject;
}
```

[V3052](https://pvs-studio.ru/ru/docs/warnings/v3052/) The original exception object 'e' was swallowed\. Stack of original exception could be lost\. ReflectionUtils\.cs 797

[V3052](https://pvs-studio.ru/ru/docs/warnings/v3052/) The original exception object 'e' was swallowed\. Stack of original exception could be lost\. ReflectionUtils\.cs 806

Согласно стандарту, если передавать exception выше по стеку вызова функций способом _throw e;_,  мы потеряем стек вызова, который был до перехвата исключения в блоке _catch_\. Для сохранения всего стека вызова и его дальнейшего продолжения, нужно просто написать одно слово _throw_ в блоке _catch_ и всё\. 

Иногда проверки излишни, а иногда их просто не хватает, как например в следующем коде:

```cpp
private static void ParseCssFontFamily(....)
{
  ....
  if (fontFamilyList == null && fontFamily.Length > 0)
  {
    if (fontFamily[0] == '"' || fontFamily[0] == '\'')
    {
      // Unquote the font family name
      fontFamily = 
        fontFamily.Substring(1, fontFamily.Length - 2);
      ....
}
```

[V3057](https://pvs-studio.ru/ru/docs/warnings/v3057/) The 'Substring' function could receive the '\-1' value while non\-negative value is expected\. Inspect the second argument\. HtmlCSSParser\.cs 645

Здесь нет проверки, что _fontFamily\.Length_ больше 1, и в следствии этого вычитания из _fontFamily\.Length_ числа 2, мы можем получить значение меньше 0\. А данная функция в таких случаях выкидывает исключение _ArgumentOutOfRangeException_\.

Безопасней было бы написать проверку:

```cpp
if (fontFamilyList == null && fontFamily.Length > 1)
```

**4\.** **WPF** **ошибка** 

DependencyProperty \- одна из самых замечательных возможностей WPF\. Создавать свойства, которые прямо из коробки могут оповестить разработчика о своём изменении \- невероятно удобно\. Но главное \- не перепутать сигнатуру для их описания, особенно важно об этом помнить, показывая примеры, потому что именно на них люди и ориентируются\.  

```cpp
public double Radius
{
  get { return (double) GetValue(RadiusProperty); }
  set { SetValue(RadiusProperty, value); }
}
public static readonly DependencyProperty 
  RadiusProperty = DependencyProperty.Register(
    "RadiusBase",
    typeof (double),
    typeof (FireworkEffect),
    new FrameworkPropertyMetadata(15.0));
```

[V3045](https://pvs-studio.ru/ru/docs/warnings/v3045/) WPF: the names of the registered property 'RadiusBase', and of the property 'Radius', do not correspond with each other\. FireworkEffect\.cs 196

В данном конкретном случае, имя, которое зарегистрировано для свойства зависимости, не совпадает с именем свойства\-обертки для доступа с DependencyProperty из кода\. Такой вариант приводит к большим проблемам при работе из XAML разметки\. WPF позволяет из XAML обратиться к простому свойству _Radius_ и прочитать от туда значение, но вот изменения данного свойства подхватываться из XAML не будут\.

На самом деле, в [PVS\-Studio](https://pvs-studio.ru/ru/pvs-studio/download/) имеется целый ряд диагностик для обнаружения ошибок в сигнатуре создания DependencyProperty \[[3044](https://pvs-studio.ru/ru/docs/warnings/v3044/), [3045](https://pvs-studio.ru/ru/docs/warnings/v3045/), [3046](https://pvs-studio.ru/ru/docs/warnings/v3046/), [3047](https://pvs-studio.ru/ru/docs/warnings/v3047/), [3048](https://pvs-studio.ru/ru/docs/warnings/v3048/), [3049](https://pvs-studio.ru/ru/docs/warnings/v3049/)\]\. Большинство ошибок такого рода приводят к падению программы, как только начинается использование классас данными свойствами зависимости\. Поэтому данные диагностики предназначены именно для того, чтобы избавить вас от поиска и анализа длинных портянок сигнатур, особенно после копирования\. Для этого, естественно, нужна регулярная проверка кода, а не только анализ финальной версии программы\.

Рассмотрим еще одно интересное срабатывание\. В данном случае сработала новая диагностика V3095\. Данная диагностика показывает места, где мы сначала обращаемся к переменной, а потом проверяем её на равенство _null_\.

```cpp
private static XmlElement AddOrphanListItems(....)
{
  Debug.Assert(htmlLiElement.LocalName.ToLower() == "li");
  ....
  XmlNode htmlChildNode = htmlLiElement;
  var htmlChildNodeName = htmlChildNode == null 
      ? null 
      : htmlChildNode.LocalName.ToLower();
  ....
}
```

V3095 The 'htmlLiElement' object was used before it was verified against null\. Check lines: 916, 936\. HtmlToXamlConverter\.cs 916

В данном случае, в условии тернарного оператора мы проверяем, что переменная _htmlChildNode_ может быть _null_\. При этом переменная _htmlChildNode_ представляет собой не более чем ссылку на переменную _htmlLiElement_\. А вот именно к переменной _htmlLiElement_ мы обращались без проверки на _null_\. В итоге, мы либо имеет код, который никогда не выполнится, либо вообще получим исключение _NullReferenceException_ в строке _htmlLiElement\.LocalName\.ToLower\(\)_\.

Кроме описанных ошибок, большое внимание к себе привлекает диагностика под номером [V3072](https://pvs-studio.ru/ru/docs/warnings/v3072/), которая предназначена для выявления наличия полей с типом, который реализует интерфейс _IDisposable_, но сам класс, где поля объявлены, не имеет подобной реализации\.

```cpp
internal class Email
{
  private readonly SmtpClient _client;
  ....
}
```

[V3072](https://pvs-studio.ru/ru/docs/warnings/v3072/) The 'Email' class containing IDisposable members does not itself implement IDisposable\. Inspect: \_client\. Email\.cs 15

С _IDisposable_ всегда было туго\. От критических ошибок, в следствии неправильного его использования, кончено, часто спасает _Finalize_, ну, по крайней мере, в стандартных классах\. Программисты нередко забивают, забывают, упускают или просто не обращают внимания на поля с типом, реализующим данный интерфейс\. Оправдать подобный код или признать в нем наличие ошибки сложно для стороннего взгляда, но есть некоторые паттерны, на которые стоит обратить внимание\. В данном Solution, подобных срабатываний набралось тоже не мало\.

* V3072 The 'HtmlLexicalAnalyzer' class containing IDisposable members does not itself implement IDisposable\. Inspect: \_inputStringReader\. HtmlLexicalAnalyzer\.cs 16
* V3072 The 'MainWindow' class containing IDisposable members does not itself implement IDisposable\. Inspect: \_customersTableAdapter, \_nwDataSet\.\.\. MainWindow\.cs 15
* V3072 The 'MainWindow' class containing IDisposable members does not itself implement IDisposable\. Inspect: \_listControl\. MainWindow\.cs 14
* V3072 The 'ThumbViewer' class containing IDisposable members does not itself implement IDisposable\. Inspect: \_annStore, \_annotationBuffer\. ThumbViewer\.xaml\.cs 31
* V3072 The 'HtmlLexicalAnalyzer' class containing IDisposable members does not itself implement IDisposable\. Inspect: \_inputStringReader\. htmllexicalanalyzer\.cs 24
* V3072 The 'MainWindow' class containing IDisposable members does not itself implement IDisposable\. Inspect: \_store\. MainWindow\.cs 20
* V3072 The 'MainWindow' class containing IDisposable members does not itself implement IDisposable\. Inspect: \_customCursor\. MainWindow\.cs 14
* V3072 The 'MainWindow' class containing IDisposable members does not itself implement IDisposable\. Inspect: \_speechSynthesizer\. MainWindow\.cs 14



## С\+\+ Ошибки

**1\. Ошибки при составлении условий инструкции if**

Для меня, конечно, было откровением, что я найду в данном Solution С\+\+ проекты, но тем не менее, ошибки есть ошибки и давайте на них посмотрим\.

Как и в C\#, начнем с различных сравнений и сразу рассмотрим ту самую С\+\+ ошибку о которой я говорил чуть выше в C\# блоке\. 

```cpp
STDMETHOD(CreateInstance)(....)
{
  ....
  T *obj = new T();
  if (NULL != obj)
  {
    ....
}
```

[V668](https://pvs-studio.ru/ru/docs/warnings/v668/) There is no sense in testing the 'obj' pointer against null, as the memory was allocated using the 'new' operator\. The exception will be generated in the case of memory allocation error\. classfactory\.h 76

Если оператор _new_ не смог выделить память, то, согласно стандарту языка C\+\+, генерируется исключение std::bad\_alloc\(\)\. Таким образом, проверять на равенство нулю не имеет смысла, т\.к\. указатель _obj_ никогда не будет равен _NULL_\. Если выделить память невозможно, то возникает исключение, которое можно обрабатывать на более высоком уровне, а проверку на равенство _NULL_ можно просто удалить\. Если исключения в приложении нежелательны, то можно использовать оператор _new_, не генерирующий исключений \(_T \*obj \= new \(std::nothrow\) T\(\)_\): в этом случае можно проверять возвращаемое значение на ноль\. В Solution встретилось еще 4 подобных проверки:

* V668 There is no sense in testing the 'colors' pointer against null, as the memory was allocated using the 'new' operator\. The exception will be generated in the case of memory allocation error\. aitdecoder\.cpp 182
* V668 There is no sense in testing the 'pixels' pointer against null, as the memory was allocated using the 'new' operator\. The exception will be generated in the case of memory allocation error\. aitencoder\.cpp 157
* V668 There is no sense in testing the 'colors' pointer against null, as the memory was allocated using the 'new' operator\. The exception will be generated in the case of memory allocation error\. aitencoder\.cpp 221
* V668 There is no sense in testing the 'bytes' pointer against null, as the memory was allocated using the 'new' operator\. The exception will be generated in the case of memory allocation error\. aitencoder\.cpp 275

Лишние условия актуальны в обоих языках программирования: 

```cpp
if (bitmapLock && bitmap)
{
  if(bitmapLock)
  {
    bitmapLock->Release();
    bitmapLock = NULL;
  }
}
```

[V571](https://pvs-studio.ru/ru/docs/warnings/v571/) Recurring check\. The 'bitmapLock' condition was already verified in line 104\. aitdecoder\.cpp 106

Некоторые программисты C\# не знают, что следующие две операции над _Nullable_ типом равнозначные:

* \_isInDesignMode \!\= null
* \_isInDesignMode\.HasValue

И делают подобные проверки:

```cpp
if (_isInDesignMode != null && _isInDesignMode.HasValue)
```

В C\+\+ любят бессмысленно проверять указатель на null, перед тем как освободить память, выделенную по адресу, на который он указывает\.

```cpp
static HRESULT OutputColorContext(....)
{
  ....
  if (pixels)
    delete[] pixels;
  ....
}
```

[V809](https://pvs-studio.ru/ru/docs/warnings/v809/) Verifying that a pointer value is not NULL is not required\. The 'if \(pixels\)' check can be removed\. aitencoder\.cpp 189

```cpp
static HRESULT OutputBitmapPalette(....)
{
  ....
  if (colors)
    delete[] colors;
  ....
}
```

[V809](https://pvs-studio.ru/ru/docs/warnings/v809/) Verifying that a pointer value is not NULL is not required\. The 'if \(colors\)' check can be removed\. aitencoder\.cpp 241

```cpp
static HRESULT OutputColorContext(....)
{
  if (bytes)
    delete[] bytes;
}
```

[V809](https://pvs-studio.ru/ru/docs/warnings/v809/) Verifying that a pointer value is not NULL is not required\. The 'if \(bytes\)' check can be removed\. aitencoder\.cpp 292

**2\. Логическая ошибка**

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

```cpp
STDMETHODIMP AitDecoder::QueryCapability(....)
{
  ....
  // If this is our format, we can do everything
  if (strcmp(bh.Name, "AIT") == 0)
  {
     *pCapability = 
       WICBitmapDecoderCapabilityCanDecodeAllImages ||
       WICBitmapDecoderCapabilityCanDecodeThumbnail ||
       WICBitmapDecoderCapabilityCanEnumerateMetadata ||
       WICBitmapDecoderCapabilitySameEncoder;
  }
  ....
}
```

[V560](https://pvs-studio.ru/ru/docs/warnings/v560/) A part of conditional expression is always true\. aitdecoder\.cpp 634

Диагностика посчитала, что часть выражения всегда истина и она права, т\.к\. слова _WICBitmapDecoderCapabilityCanDecodeXXX_ представляют собой просто значения _enum_ с именем _WICBitmapDecoderCapabilities_:

```cpp
enum WICBitmapDecoderCapabilities
{
  WICBitmapDecoderCapabilitySameEncoder = 0x1,
  WICBitmapDecoderCapabilityCanDecodeAllImages = 0x2,
  WICBitmapDecoderCapabilityCanDecodeSomeImages = 0x4,
  WICBitmapDecoderCapabilityCanEnumerateMetadata = 0x8,
  WICBitmapDecoderCapabilityCanDecodeThumbnail = 0x10,
  WICBITMAPDECODERCAPABILITIES_FORCE_DWORD = 0x7fffffff
};
```

Как следствие, вероятно, что кто\-то просто перепутал символы и вместо побитового ИЛИ "\|" написали логическое ИЛИ "\|\|"\. В отличии от C\# компилятора, С\+\+ это легко проглотил\.

**3\. Ошибки в инициализации и при присвоении переменных**

Кончено, после рефакторинга часто остаются два раза подряд проинициализированные переменные\.

```cpp
STDMETHODIMP BaseFrameEncode::WritePixels(....)
{
   result = S_OK;
   ....
   result = factory->CreateBitmapFromMemory(....);
}
```

[V519](https://pvs-studio.ru/ru/docs/warnings/v519/) The 'result' variable is assigned values twice successively\. Perhaps this is a mistake\. Check lines: 269, 279\. baseencoder\.cpp 279

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

```cpp
STDMETHODIMP AitFrameEncode::Commit()
{
   HRESULT result = E_UNEXPECTED;
   result = BaseFrameEncode::Commit();
   ....
}
```

[V519](https://pvs-studio.ru/ru/docs/warnings/v519/) The 'result' variable is assigned values twice successively\. Perhaps this is a mistake\. Check lines: 320, 321\. aitencoder\.cpp 321

## Заключение

Бытует мнение, что C\# код менее подвержен ошибкам, чем С\+\+; в определенных случаях это действительно так\. Однако, интересный факт состоит в том, что основная масса ошибок находится не в специфических конструкциях, а в простых выражениях\. Например, в условиях инструкции _if_\. Статический анализатор кода для [PVS\-Studio](https://pvs-studio.ru/ru/pvs-studio/) C, C\+\+ и C\# позволит вам контролировать качество вашего кода и всеми силами будет уберегать вас от фатальных ошибок, которые могут дойти до вашего пользователя\.