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.
Дополнительная информация:
- Wikipedia. Таблица виртуальных методов.
- Wikipedia. Виртуальный метод (виртуальная функция).
- Wikipedia. Деструктор.
- Сергей Олендаренко. Виртуальные функции и деструктор.
Выявляемые диагностикой ошибки классифицируются согласно ГОСТ Р 71207–2024 как критические и относятся к типу: Ошибки управления динамической памятью (выделения, освобождения, использования освобожденной памяти), Ошибки утечек памяти, незакрытых файловых дескрипторов и дескрипторов сетевых соединений. |
Данная диагностика классифицируется как:
|
Взгляните на примеры ошибок, обнаруженных с помощью диагностики V599. |