AUTOSAR C++14 Rule A12-4-2

Если публичный деструктор класса не является виртуальным, то класс должен быть объявлен окончательным

Описание

Определение правила

Если публичный деструктор класса не является виртуальным, то класс должен быть объявлен окончательным.

Объяснение

В C++, когда любой объект производного класса уничтожается, сначала вызывается деструктор его класса, а затем вызываются деструкторы базовых классов. Иерархии классов также могут быть полиморфными. Можно объявить указатель базового класса и назначить ему производный объект класса. Чтобы безопасно уничтожить объекты, принадлежащие иерархии классов, объявите public классифицирует деструкторы как virtual. Рассмотрим этот код, где уничтожаются два указателя базовых классов, которые указывают на производные объекты.

class Base{
public:
	virtual	~Base();
	//..
};

class Derived : public Base{
public:
	~Derived();
	//..
};
class Base2{
public:
	~Base2();
	//..
};

class Derived2 : public Base2{
public:
	~Derived2();
	//...
};
int main(){
	
	Base* ptr = new Derived;
	Base2* ptr2 = new Derived2;
	delete ptr;
	delete ptr2;
}

  • Объект ptr - указатель на класс Base который указывает на объект класса Derived. Когда ptr удаляется, сначала вызывается деструктор производного класса, а затем вызывается деструктор базового класса. Хотя ptr является объектом базового класса, правильные деструкторы вызываются, чтобы освободить все полученные ресурсы, потому что public деструкторы в этой иерархии классов объявляются как virtual.

  • Когда указатель ptr2 удален, деструктор вызывается только для базового класса, поскольку public деструкторы в этой иерархии классов являются невиртуальными. Такого рода неполное уничтожение является неопределенным поведением, которое может привести к утечкам памяти и неожиданному прекращению выполнения кода.

Чтобы предотвратить неопределенное поведение, не используйте классы с public невиртуальные деструкторы как базовые классы. Объявить такие классы как final чтобы указать, что эти классы не являются базовыми классами и новые классы не могут быть выведены из них.

Реализация Polyspace

Polyspace® помечает объявление класса, если оба этих операторов являются true:

  • The public деструктор класса не объявляется как virtual.

  • Класс не объявлен final.

Поиск и устранение проблем

Если вы ожидаете нарушения правил, но не видите его, обратитесь к разделу «Стандартные нарушения кодирования не отображаются».

Примеры

расширить все

В этом примере показано, как Polyspace помечает базовые классы, которые имеют общедоступные невиртуальные деструкторы.

#include<cstdint>
class Base{    //Noncompliant
public:
	~Base();
	//..
};

class Derived : public Base{  //Noncompliant
public:
	~Derived();
	//..
};
class Base2 final{  //Compliant
public:
	~Base2();
	//..
};

//class Derived2 : public Base2{ //Compilation error
//public:
//	~Derived2();
//	//...
//};
int main(){
	
	Base* ptr = new Derived;
	//	Base2* ptr2 = new Derived2;  //Compilation Error
	delete ptr;
	//	delete ptr2;
}

Классы Base и Derived иметь общедоступные невиртуальные деструкторы. В main(), когда ptr разрушен, только ~Base() вызывается, что приводит к частичному уничтожению объекта с заострением. Такое поведение является неопределенным поведением, которое может привести к утечке памяти и неожиданному завершению программы. Polyspace помечает объявление обоих Base и Derived.

Класс Base2 имеет общедоступный невиртуальный деструктор. Base2 соответствует этому правилу, потому что он объявлен как final. Вывод любого класса из Base2 приводит к отказу компиляции. Следовательно, вы не можете объявить указатель на класс Base2 который указывает на объект производного класса. Объявление классов с общедоступными невиртуальными деструкторами как final предотвращает неопределенное поведение и может защитить код от утечек памяти и неожиданного отключения программы.

Этот пример показывает, что Polyspace позволяет невиртуальные деструкторы, когда они объявлены protected.

#include<cstdint>
class Base{    //Compliant
protected:
	~Base();
	//..
};

class Derived : public Base{  //Compliant
protected:
	~Derived();
	//..
};

int main(){
	
	Base* ptr = new Derived;
	delete ptr;//Compilation error
}

Невиртуальные деструкторы, объявленные как protected соответствуют этому правилу. Потому что деструктор для Base защищен, оператор delete ptr; приводит к отказу компиляции. Объявление невиртуальных деструкторов как protected может предотвратить утечки памяти и неожиданное отключение программы. Когда нефинальные классы имеют невиртуальные деструкторы, объявленные как protected, классы соответствуют этому правилу, и Polyspace не помечает их.

Проверяйте информацию

Группа: Специальные функции представителей
Категория: Консультационные, Автоматизированные
Введенный в R2020b