﻿# V668\. Possible meaningless check for null, as memory was allocated using 'new' operator\. Memory allocation will lead to an exception\.

Анализатор обнаружил ситуацию, когда значение указателя возвращаемого оператором 'new' сравнивается с нулём\. Как правило, это значит, что программа при невозможности выделить память будет вести себя не так, как ожидает программист\.

Если оператор 'new' не смог выделить память, то согласно стандарту языка Си\+\+, генерируется исключение std::bad\_alloc\(\)\. Таким образом проверять указатель на равенство нулю не имеет смысла\. Рассмотрим простейший случай:

```cpp
MyStatus Foo()
{
  int *p = new int[100];
  if (!p)
    return ERROR_ALLOCATE;
  ...
  return OK;
}
```

Указатель 'p' никогда не будет равен нулю\. Функция никогда не вернет константное значение ERROR\_ALLOCATE\. Если выделить память невозможно, то возникнет исключение\. Исправим код наиболее простым образом:

```cpp
MyStatus Foo()
{
  try
  { 
    int *p = new int[100];
    ...
  }
  catch(const std::bad_alloc &)
  {
    return ERROR_ALLOCATE;
  }
  return OK;
}
```

Отметим, что приведенный пример исправленного кода очень плох\. Идеология работы с исключениями совсем иная\. Исключения как раз позволяют избавиться от множества проверок и возвращаемых статусов\. Лучше позволить исключению выйти за пределы функции 'Foo' и обработать его где\-то на более высоком уровне\. К сожалению, рассмотрение использования исключений выходит за рамки документации\.

Рассмотрим, как подобная ошибка может выглядеть на практике\. Вот код, взятый из реального приложения:

```cpp
// For each processor; spawn a CPU thread to access details.
hThread = new HANDLE [nProcessors];
dwThreadID = new DWORD [nProcessors];
ThreadInfo = new PTHREADINFO [nProcessors];
// Check to see if the memory allocation happenned.
if ((hThread == NULL) ||
    (dwThreadID == NULL) ||
    (ThreadInfo == NULL))
{
  char * szMessage = new char [128];
  sprintf(szMessage,
          "Cannot allocate memory for "
          "threads and CPU information structures!");
  MessageBox(hDlg, szMessage, APP_TITLE, MB_OK|MB_ICONSTOP);
  delete szMessage;
  return false;
}
```

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

Частой причиной описанных проблем, является изменение в поведении оператора 'new'\. Во времена Visual C\+\+ 6\.0, оператор 'new' в случае ошибки возвращал NULL\. Следующие версии Visual C\+\+ следуют стандарту и генерируют исключение\. Помните про это изменение поведения\. Таким образом, если вы адаптируете старый проект для сборки современным компилятором, вам стоит уделить повышенное внимание диагностике V668\.



**Примечание N1**\. Анализатор не будет выдавать предупреждение, если используется placement new или "new \(std::nothrow\) T"\. Пример такого кода:

```cpp
T * p = new (std::nothrow) T; // OK
if (!p) {
  // An error has occurred.
  // No storage has been allocated and no object constructed.
  ...
}
```

**Примечание N2**\. Есть возможность слинковать проект с nothrownew\.obj\. В этом случае, оператор new не будет генерировать исключение\. Такой возможностью, например, пользуются разработчики драйверов\. Подробнее: [new and delete operators](https://stackoverflow.com/questions/550451/will-new-return-null-in-any-case)\. В этом случае, просто отключите предупреждение V668\.



**Дополнительные материалы по данной теме:**

1. Wikipedia\. [Placement syntax](https://en.wikipedia.org/wiki/Placement_syntax)\.
1. Microsoft Support\. [Operator new does not throw a bad\_alloc exception on failure in Visual C\+\+](https://docs.microsoft.com/ru-ru/cpp/cpp/new-and-delete-operators?view=vs-2019)\.
1. Stack Overflow\. [Will new return NULL in any case?](https://stackoverflow.com/questions/550451/will-new-return-null-in-any-case)