C and C++


LANG.STRUCT.VCALL_IN_DTOR : Virtual Call in Destructor

Summary

A virtual member function is called from a destructor.

This can lead to unexpected and potentially dangerous behavior. During execution of a base class B's destructor, when not in an even deeper base class's destructor, any virtual calls through the this pointer will resolve as if B is the dynamic type (most derived type) of this.

For inline destructors, a warning will only be issued if the destructor is invoked at least once.

Properties

Class Name Virtual Call in Destructor
Significance reliability
Mnemonic LANG.STRUCT.VCALL_IN_DTOR
Categories
AUTOSARC++14 AUTOSARC++14:M12-1-1 An object's dynamic type shall not be used from the body of its constructor or destructor.
MisraC++2008 MisraC++2008:12-1-1 An object's dynamic type shall not be used from the body of its constructor or destructor.
MisraC++2023 MisraC++2023:15.1.1 An object's dynamic type shall not be used from within its constructor or destructor
CERT-CPP CERT-CPP:OOP50-CPP Do not invoke virtual functions from constructors or destructors
JSF++ JSF++:70.1 An object shall not be improperly used before its lifetime begins or after its lifetime ends.
  JSF++:71.1 A class's virtual functions shall not be invoked from its destructor or any of its constructors.
Availability Available for C++ only (not C).
Enabling Checks for this warning class are enabled by default. To disable them, add the following WARNING_FILTER rule to the project configuration file.
WARNING_FILTER += discard class="Virtual Call in Destructor"

Example

namespace lang_struct_vcall_in_dtor {

  // Code with implicit inline destructor invocation. 

  class BaseExplicit {
      virtual void virtual_cleanup(void) {}
    public:
      ~BaseExplicit() {
          this->virtual_cleanup(); // 'Virtual Call in Destructor' warning issued here.
                                   //   This call to virtual_cleanup() will always invoke BaseExplicit::virtual_cleanup(),
                                   //   which is probably not what the author intends.
      }
  };

  class DerivedExplicit : BaseExplicit {
      int  *iptr;
      virtual void virtual_cleanup(void) override {delete iptr;}
    public:
      DerivedExplicit() {iptr = new int;}
  };

  void use_base_explicit(BaseExplicit *be){
      delete be;                                        // Explicit invocation of inline destructor.
  }

  // Code with implicit destructor invocation. 

  class BaseImplicit {
      virtual void virtual_cleanup(void) {}
    public:
      ~BaseImplicit() {
          this->virtual_cleanup(); // Two 'Virtual Call in Destructor' warnings issued here.
                                   // - one for the virtual call in BaseImplicit::~BaseImplicit()
                                   // - one for the virtual call in DerivedImplicit::~DerivedImplicit()
      }
  };

  class DerivedImplicit : BaseImplicit {
      int *iptr;
      virtual void virtual_cleanup(void) override {delete iptr;}
    public:
        DerivedImplicit() {iptr = new int;  *iptr=5;}
        int value(void){return *iptr;}
  };

  int use_derived_implicit(void){
      DerivedImplicit di;
      return di.value();
                                                        // Implicit invocation of inline DerivedImplicit destructor
                                                        // (and then BaseImplicit destructor) when di goes out of scope.
  }
}

Relevant Configuration File Parameters

The following configuration file parameters affect checks for this warning class.