Voyager
Voyager

Reputation: 539

Memory leak with Qwt

I am developing a small plotter application with Qt 5.8 and Qwt 6.1.3. Though I think I understand Qwt's memory management approach correctly, I seem to have memory leaks in my application due to QwtPlotItems I'm using; such as QwtPlotMarker and QwtPlotCurve. I have read this and this as well as the documentation. I follow the rules given there, however I still have memory leaks with plot items.

In my application there is a QwtPlot object that is alive at all times while the application is running. Plot items such as QwtPlotMarker and QwtPlotCurve are being attach()-ed and detach()-ed during run time. What I do is, I don't call delete for any QwtPlotItem, I use raw pointers for Qwt objects.

I'm not sure if once a QwtPlotITem is detach()-ed it is also deleted. I have seen void QwtPlotDict::removeItem(QwtPlotItem* item) in the documentation and I'm not sure if I should use it to delete attach()-ed QwtPlotItems, because what it seems is that after detach(), QwtPlotItems are still alive on the heap.

I would appreciate any guidance regarding memory management in Qwt.

Update:

Below is a better example. Without the second for loop where I'm detach()-ing QwtPlotCurves, memory usage is 8.2 Mbs. With the second for loop but without the delete v[i]; // MANUALLY DELETING QWTPLOTITEM OBJECT, memory usage is still 8.2 Mbs. With the second for loop AND the delete v[i]; // MANUALLY DELETING QWTPLOTITEM OBJECT line, the memory usage is 5.2 Mbs. So I think it is needed to manually delete QwtPlotItems in Qwt.

#include <QApplication>
#include <qwt_plot.h>
#include <qwt_plot_curve.h>
#include <vector>

int main(int argc, char *argv[]) {
    QApplication a(argc, argv);
    QwtPlot* plot = new QwtPlot;

    std::vector<QwtPlotCurve*> v;
    double x[5] = {0, 1, 2, 3, 4};
    double y1[5] = {0, 1.5, 0.3, 2.7, 3.0};
    double y2[5] = {0, 0.5, 0.2, 2.0, 1.6};

    for(size_t i = 0; i < 2000; i++) {
        double y1[5] = {0*i, 1.5*i, 0.3*i, 2.7*i, 3.0*i};
        QwtPlotCurve* plotCurve1 = new QwtPlotCurve("CurveXY1");
        plotCurve1->setSamples(&x[0], &y1[0], 5);
        plotCurve1->attach(plot);
        v.push_back(plotCurve1);
    }

    for(size_t i = 0; i < 1900; i++) {
        v[i]->detach();
        delete v[i]; // MANUALLY DELETING QWTPLOTITEM OBJECT
    }

    plot->replot();
    plot->show();

    return a.exec();
}

In above example, both if()s have conditions that are true. So plotCurve2 was not deleted after detach().

Upvotes: 1

Views: 1292

Answers (1)

Joseph Ireland
Joseph Ireland

Reputation: 2505

I think you are misunderstanding the forum posts regarding pointer ownership.

In qwt, QwtPlotItems are all owned by the QwtPlot that they are attach()ed to, so if you delete that plot, all of the QwtPlotItems will be deleted.

If you call detach(), then ownership is transferred to the caller, so you need to delete it yourself (or .attach() it to another plot). If it were deleted for you then attaching to another plot would not be possible.

item.detach(); delete item is perfectly fine regarding memory management, and the delete is necessary.

An alternative would be to just delete it directly (without calling .detach()). The destructor will detach it for you, and then there are no ownership questions or risks of memory leaks.

A further alternative would be to store a std::vector<std::unique_ptr<QwtPlotItem>> (or QList std::set/whatever container you want) and just erase them from the vector when you are done. That will definitely not have memory leaks, but you need to ensure that the vector is created after the plot and destroyed before it, or you will get double deletes (e.g. place the vector afterwards on the stack, or after the plot inside your object).

Upvotes: 4

Related Questions