Main Content

AUTOSAR C++14 Rule A12-4-2

If a public destructor of a class is non-virtual, then the class should be declared final

Since R2020b

Description

Rule Definition

If a public destructor of a class is non-virtual, then the class should be declared final.

Rationale

In C++, when any object of a derived class is destroyed, first the destructor of its class is invoked, and then the destructors of the base classes are invoked. Class hierarchies can also be polymorphic. You can declare a base class pointer and assign a derived class object to it. To safely destroy objects belonging to a class hierarchy, declare the public class destructors as virtual. Consider this code where two base class pointers that point to derived objects are destroyed.

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;
}

  • The object ptr is a pointer of class Base that points to an object of class Derived. When ptr is deleted, the destructor of the derived class is called first, and then the destructor of the base class is called. Even though ptr is a base class object, the correct destructors are called to release all acquired resources because the public destructors in this class hierarchy are declared as virtual.

  • When the pointer ptr2 is deleted, the destructor of only the base class is called because the public destructors in this class hierarchy are nonvirtual. This kind of incomplete destruction is undefined behavior, which can lead to memory leaks and unexpected termination of code execution.

To prevent undefined behavior, do not use classes with public nonvirtual destructors as base classes. Declare such classes as final to specify that these classes are not base classes and new classes cannot be derived from them.

Polyspace Implementation

Polyspace® flags a class declaration if both these statements are true:

  • The public destructor of the class is not declared as virtual.

  • The class is not declared final.

Troubleshooting

If you expect a rule violation but Polyspace does not report it, see Diagnose Why Coding Standard Violations Do Not Appear as Expected.

Examples

expand all

This example shows how Polyspace flags base classes that have public nonvirtual destructors.

#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;
}

The classes Base and Derived have public nonvirtual destructors. In main(), when ptr is destroyed, only ~Base() is called, resulting in partial destruction of the pointed-to object. This behavior is undefined behavior that can lead to memory leak and unexpected program termination. Polyspace flags the declaration of both Base and Derived.

The class Base2 has a public nonvirtual destructor. Base2 is compliant with this rule because it is declared as final. Deriving any class from Base2 results in compilation failure. Consequently, you cannot declare a pointer of class Base2 that points to an object of a derived class. Declaring classes with public nonvirtual destructors as final prevents undefined behaviors and can protect the code from memory leaks and unexpected program termination.

This example shows that Polyspace allows nonvirtual destructors when they are declared 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
}

Nonvirtual destructors declared as protected are compliant with this rule. Because the destructor for Base is protected, the statement delete ptr; causes a compilation failure. Declaring nonvirtual destructors as protected can prevent memory leaks and unexpected program termination. When nonfinal classes have nonvirtual destructors declared as protected, the classes comply with this rule and Polyspace does not flag them.

Check Information

Group: Special member functions
Category: Advisory, Automated

Version History

Introduced in R2020b