0

I'm trying to call QObject::connect by passing a lambda function as the 3rd parameter.

However, I Visual Visual Studio gives me the following error:

Unhandled exception at 0x0000000066B48265 (Qt5Cored.dll) in QCustomPlotInVS_FirstTry.exe: 0xC0000005: Access violation reading location 0x0000000000000008.

Here is the top 3 lines on the Call Stack when the error occurs:

Qt5Cored.dll!QListData::size() Line 91
QCustomPlotInVS_FirstTry.exe!QList::size() Line 132 QCustomPlotInVS_FirstTry.exe!QCustomPlot::graph(int index) Line 9657

Line 91 in qList.h is: inline int size() const { return d->end - d->begin; }

I think I'm getting this error because I'm incorrectly trying to use a pointer (i.e. the QCustomPlot* plot) with a lambda function.

Is my syntax for the lambda function correct? If not, what am I doing wrong?

Here is the function in which I call the QObject::connect with a lambda function:

void setupRealTimePlot(QCustomPlot* plot, QTimer* dataTimer)
{
    plot->addGraph(); // blue line
    plot->graph(0)->setPen(QPen(Qt::blue));
    plot->graph(0)->setBrush(QBrush(QColor(240, 255, 200)));
    plot->graph(0)->setAntialiasedFill(false);
    plot->addGraph(); // red line
    plot->graph(1)->setPen(QPen(Qt::red));
    plot->graph(0)->setChannelFillGraph(plot->graph(1));

    plot->addGraph(); // blue dot
    plot->graph(2)->setPen(QPen(Qt::blue));
    plot->graph(2)->setLineStyle(QCPGraph::lsNone);
    plot->graph(2)->setScatterStyle(QCPScatterStyle::ssDisc);
    plot->addGraph(); // red dot
    plot->graph(3)->setPen(QPen(Qt::red));
    plot->graph(3)->setLineStyle(QCPGraph::lsNone);
    plot->graph(3)->setScatterStyle(QCPScatterStyle::ssDisc);

    plot->xAxis->setTickLabelType(QCPAxis::ltDateTime);
    plot->xAxis->setDateTimeFormat("hh:mm:ss");
    plot->xAxis->setAutoTickStep(false);
    plot->xAxis->setTickStep(2);
    plot->axisRect()->setupFullAxesBox();

    // make left and bottom axes transfer their ranges to right and top axes:
    QObject::connect(plot->xAxis, SIGNAL(rangeChanged(QCPRange)), plot->xAxis2, SLOT(setRange(QCPRange)));
    QObject::connect(plot->yAxis, SIGNAL(rangeChanged(QCPRange)), plot->yAxis2, SLOT(setRange(QCPRange)));

    // setup a timer that repeatedly calls MainWindow::realtimeDataSlot:
    QObject::connect(dataTimer, &QTimer::timeout, 
        [&]()
        {
            // calculate two new data points:
            double key = QDateTime::currentDateTime().toMSecsSinceEpoch()/1000.0;
            static double lastPointKey = 0;
            if (key-lastPointKey > 0.01) // at most add point every 10 ms
            {
            double value0 = qSin(key); //qSin(key*1.6+qCos(key*1.7)*2)*10 + qSin(key*1.2+0.56)*20 + 26;
            double value1 = qCos(key); //qSin(key*1.3+qCos(key*1.2)*1.2)*7 + qSin(key*0.9+0.26)*24 + 26;
            // add data to lines:
            plot->graph(0)->addData(key, value0);
            plot->graph(1)->addData(key, value1);
            // set data of dots:
            plot->graph(2)->clearData();
            plot->graph(2)->addData(key, value0);
            plot->graph(3)->clearData();
            plot->graph(3)->addData(key, value1);
            // remove data of lines that's outside visible range:
            plot->graph(0)->removeDataBefore(key-8);
            plot->graph(1)->removeDataBefore(key-8);
            // rescale value (vertical) axis to fit the current data:
            plot->graph(0)->rescaleValueAxis();
            plot->graph(1)->rescaleValueAxis(true);
            lastPointKey = key;
            }
            // make key axis range scroll with the data (at a constant range size of 8):
            plot->xAxis->setRange(key+0.25, 8, Qt::AlignRight);
            plot->replot();

            // calculate frames per second:
            static double lastFpsKey;
            static int frameCount;
            ++frameCount;
            if (key-lastFpsKey > 2) // average fps over 2 seconds
            {
            lastFpsKey = key;
            frameCount = 0;
            }
        });

    dataTimer->start(0); // Interval 0 means to refresh as fast as possible

}
0

1 Answer 1

2

You are capturing stack-allocated variables by reference (first offender: plot) in a closure that is going to be called later; all that stuff is going to be garbage once your closure is called. Capture by value instead.

Sign up to request clarification or add additional context in comments.

2 Comments

You're answer is correct. I changed the [&](){//...} to [=](){//...} and it worked. However, it's not clear to me why. I thought if I captured by value it would create a copy of the variable(s) (in my case QCustomPlot* plot), then any changes to the copy would not apply to the original variable. I think I just realized that my concern is wrong because copying a pointer will give a new variable that still points to the object I want to modify. Does my interpretation seem correct?
Exactly. You may get it more easily resolving the references as pointers: capturing a local pointer variable by reference is like storing a pointer to it inside a double pointer. When later you try to use it, it is pointing to a local variable that no longer exist. Capturing it by value, instead, is like creating a new QCustomPlot * which point to the original object (the value of the pointer is the address of the pointed object).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.