exponenta event banner

Правило AUTOSAR C++ 14 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:

  • 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