PVS-Studio.com logo
>
>
>
V599. The virtual destructor is not pre…


V599. The virtual destructor is not present, although the 'Foo' class contains virtual functions.

Анализатор обнаружил потенциальную ошибку, связанную с отсутствием в базовом классе виртуального деструктора.

Чтобы анализатор выдал предупреждение V599 необходимо, чтобы выполнились следующие условия:

  • Объект класса уничтожается с помощью оператора delete.
  • Класс имеет хотя бы одну виртуальную функцию.

Наличие виртуальных функций говорит о том, что класс могут использовать полиморфно. В этом случае виртуальный деструктор необходим, чтобы корректно разрушить объект.

Рассмотрим пример кода.

class Father
{
public:
  Father() { .... }
  ~Father() { .... } 
  virtual void Foo() { .... }
};

class Son : public Father
{
public:
  int *buffer;
  Son() : Father() { buffer = new int[1024]; }
  ~Son() { delete[] buffer; }
  virtual void Foo() { .... }
};

....
Father *object = new Son();
delete object;              // Calls object->~Father(),
                            // not object->~Son()!!

Нижеприведённый код является некорректным и приводит к утечке памяти. В момент уничтожения объекта (delete object;) вызывается только деструктор в классе Father. Чтобы вызвать деструктор класса 'Son' необходимо сделать деструктор виртуальным.

Корректный код:

class Father
{
public:
  Father() { .... }
  virtual ~Father() { .... } 
  virtual void Foo() { .... }
};

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

Намного больше проблем позволяют выявлять предупреждения компиляторов, например, C4265 в MSVC и Wdelete-non-virtual-dtor в GCC/Clang. Это очень полезные предупреждения, но по умолчанию они выключены. Возможная причина: они дают много срабатываний в коде, где используется паттерн примесь (подмешивание, mixin). При использовании этого паттерна возникает множество интерфейсных классов. Они содержат виртуальные функции, но виртуальный деструктор в них не нужен.

Можно сказать, что диагностическое правило V599 является частным случаем описанных ранее предупреждений компиляторов. Оно дает меньше ложных срабатываний, но, к сожалению, позволяет выявить меньшее количество дефектов. Если вы хотите провести более тщательный анализ своего кода, то включите предупреждение C4265.

P.S. К сожалению, всегда объявлять деструктор виртуальным не является идеальной практикой программирования. Это приводит к дополнительным накладным расходам, так как в классе появляется указатель на таблицу виртуальных методов.

P.P.S. Родственным диагностическим правилом является V689.

Дополнительная информация:

Выявляемые диагностикой ошибки классифицируются согласно ГОСТ Р 71207–2024 как критические и относятся к типу: Ошибки управления динамической памятью (выделения, освобождения, использования освобожденной памяти), Ошибки утечек памяти, незакрытых файловых дескрипторов и дескрипторов сетевых соединений.

Данная диагностика классифицируется как:

Взгляните на примеры ошибок, обнаруженных с помощью диагностики V599.