c++qtinheritancememory-managementqcustomplot

Correct allocation and deallocation of a subclassed QCPGraph


I'm using QCustomPlot and have sub-classed QCPGraph in order to provide a drawable graph.

class QCPDrawableGraph : public QCPGraph {
    Q_OBJECT
public:
    QCPDrawableGraph(QCPAxis* x, QCPAxis* y) : QCPGraph(x,y) {
        //do stuff
    }
    virtual ~QCPDrawabelGraph() {} // necessary?
    //class stuff
};

Usually, one would create new graphs by

QCustomPlot plot(parent); //where parent is the parent widget of the gui
QCPGraph* gr = plot->addGraph(); // in case of QCPGraphs or
QCPGraph* gr = new QCPGraph(plot->xAxis,plot->yAxis); // as with all other QCPAbstractPlottables

Would I use my own class just like

QCPDrawableGraph* dgr = new QCPDrawableGraph(plot->xAxis,plot->yAxis); //?

Does the destructor of QCustomPlot still take care of the de-allocation in the end?


Solution

  • The general concept of QWidgets memory management is that parent widgets care about deletion of children if they are deleted itself.

    A QWidget becomes child of another if either the parent is given in constructor (nearly every widget constructor offers a parent pointer) or the child is added to parent widget.

    This is the case for OP's QCPDrawableGraph as well.

    It is explicitly mentioned in the doc. of QPCGraph (Constructor & Destructor Documentation):

    The created QCPGraph is automatically registered with the QCustomPlot instance inferred from keyAxis. This QCustomPlot instance takes ownership of the QCPGraph, so do not delete it manually but use QCustomPlot::removePlottable() instead.

    As the constructor of OP's QCPDrawableGraph

    QCPDrawableGraph(QCPAxis* x, QCPAxis* y) : QCPGraph(x,y) {
        //do stuff
    }
    

    calls the base constructor this behavior should be inherited properly.


    Concerning the destruction a little sample:

    #include <iostream>
    
    struct Base {
      virtual ~Base() { std::cout << "Base::~Base()\n"; }
    };
    
    struct Derived: Base {
      ~Derived() { std::cout << "Derived::~Derived()\n"; }
    };
    
    int main()
    {
      Base *p = new Derived();
      delete p;
      return 0;
    }
    

    Output:

    Derived::~Derived()
    Base::~Base()
    

    Live Demo on ideone

    Notes:

    1. The destructor ~Derived() is virtual even without the virtual keyword because the destructor of its base class Base is.

    2. The destructor ~Derived() is called first though by deleting a pointer to base class Base. (That's the intention of virtual destructors.)

    3. The destructors of all base classes are called as well (as well as constructors but in reverse order).