Base class lacks destructor

A class defines virtual member functions but does not define any destructor.

This error indicates that a class contains both virtual member functions but no destructor was defined. In that case the compiler will generate a trivial destructor which is public but non-virtual. Since this class has virtual member functions, we expect it to be used as a base class. The use of non-virtual destructors in base classes is dangerous because it can cause objects to be torn down incorrectly. The example below illustrates the problem.

Marking a destructor as private makes it impossible to use that class as a base class because the destructor of a derived class would not be able to access the destructor of the base class as it is required to do. A protected non-virtual destructor is just as bad as a public non-virtual destructor; the only difference is that the bad thing happens only inside the member functions of the derived class. Therefore the only good choices for base class destructors is public virtual or protected virtual.

Marking a destructor as protected makes it impossible to delete instances of that class. This is desirable when implementing an object that wants to control its own lifetime, for example by reference counting. In almost all other cases, a public virtual destructor is the right choice.

ID

Observation

Description

1

Definition

This shows where the class was defined

Example

          
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

class evil {
public:
    // bad: should declare virtual ~evil() {}
    virtual void say_hi() { printf("I am evil\n"); }
};

// class with a non-trivial destructor
class victim : public evil {
protected:
    char * m_string;
public:
    victim() { m_string = new char[40]; }
    ~victim() { delete m_string; }

    // copy constructor
    victim::victim(const victim & source)
      : m_string(new char[40])
    {
        for (int i = 0; i < 40; i++) {
            m_string[i] = source.m_string[i];
        }
    }

    // assignment operator
    victim& victim::operator=(const victim & source)
    {
        for (int i = 0; i < 40; i++) {
            m_string[i] = source.m_string[i];
        }
        return *this;
    }

};

int main(int argc, char **argv)
{
    evil* p = new victim(); // allocates m_string
    p->say_hi();
    delete p;
    // Calls ~evil, but not ~victim because ~evil is not virtual
    // therefore m_string is never freed
};
        

Copyright © 2010, Intel Corporation. All rights reserved.