Unicorn with delicious cookie
Мы используем куки, чтобы пользоваться сайтом было удобно.
Хорошо
to the top
>
>
>
V599. The virtual destructor is not...
menu mobile close menu
Проверка проектов
Дополнительная информация
toggle menu Оглавление

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

14 Мар 2025

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

Чтобы анализатор выдал предупреждение 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 как критические и относятся к типу: Ошибки управления динамической памятью (выделения, освобождения, использования освобожденной памяти) [* см. примечание касательно языков C#, Java], Ошибки утечек памяти, незакрытых файловых дескрипторов и дескрипторов сетевых соединений [* см. примечание касательно языков C#, Java].

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

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