Home > Net >  Qt zombies: Calling functions containing new with QTimer
Qt zombies: Calling functions containing new with QTimer

Time:09-19

I'm trying to display a dynamically updating table using QTimer with a refresh rate of 1s. I'm calling the function create_table which in turn calles create_title. The code runs without complaints but tracking memory usage one finds that it keeps creeping up steadily till the program becomes unresponsive, or crashes.

void MainWindow::TableDisplay(QWidget *tab) {
    auto timer = new QTimer(this);
    connect(timer, &QTimer::timeout, [refreshed_table_data, tab, this]() {
            auto tableView = create_table(tab, refreshed_table_data, "My table");
    });
    timer->start(1000);
}

The culprits seem to be the various new statements (indicated by comments in my code) which seem to create a fresh zombies/leak every time QTimer runs a loop.

auto create_title(const std::string &title, QWidget * widget) {
    auto tableTitle = new QLabel(title.c_str(), widget); // <-- new
    tableTitle->setAlignment(Qt::AlignLeft);
    tableTitle->show();
}
auto create_table(QWidget * tab,
                  const std::vector<std::string> &v,
                  const std::string &title) {
    auto tableView = new QTableView(tab); // <-- new
    auto model = new MyModel(v, tab); // <-- new
    tableView->setModel(model);
    tableView->setStyle(new QProxyStyle(QStyleFactory::create("Fusion"))); // <-- new
    tableView->setHorizontalHeader(new QHeaderView(Qt::Horizontal)); // <-- new
    create_title(title, tab);
    tableView->show();
    return tableView;
}

One solution could be to have the pointers initalized by new defined as member variables of MainWindow so that they are defined only once. But if I'm calling several such timed-functions, it would quickly become cumbersome, even more so when one considers there are rendering elements such as the line new QProxyStyle(QStyleFactory::create("Fusion")) etc which would then need to be accorded the status of member variables.

I tried wrapping the new statements with QScopePointers but unfortunately the instances get destroyed right after create_table goes out its scope, resulting in no rendering of the table graphics.

What's the right way of writing create_table without creating zombies?

CodePudding user response:

For the question itself: Your createTable method could call QTimer::singleShot to schedule an update one second later.

auto create_table(QWidget * tab,
                  const std::vector<std::string> &v,
                  const std::string &title) {
    ...
    QTimer::singleShot(1000 /*ms*/, this /*context*/, [this, tab, v, title]() {
            create_table(tab, v, title);
    });
    return tableView;
}

However, as Igor noted, this whole approach seems backwards. The model should update itself, preferably event-based but if it has to poll external resources, it may have to use a timer itself.

Setting an entirely new model for a view is very expensive (because the view has to create everything from scratch) and can have annoying side-effects on the GUI side.

  • Related