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® отмечает объявление класса, если оба этих оператора верны:

  • 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