本文介绍了带有父级的QSqlQueryModel-应用程序崩溃的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我对Qt相当陌生,也许这就是为什么我不能完全理解儿童父母概念的原因.我需要执行一些sql查询.我设置了QSqlQuery,执行准备和绑定"操作并执行它.接下来,我将其传递给模型并显示数据.关闭窗口时发生问题-我收到内存冲突错误.仅当我与父代一起创建模型时,才会发生该错误.这是代码:

I am rather new to Qt, maybe that's why I cant fully understand the child-parent concept. I need to perform some sql query. I set the QSqlQuery, perform the "prepare and bind" operation and exec it. Next I pass it to the model and display the data. The problem occurs when closing the window - I get a memory violation error. The error occurs only, when I create the model with a parent. Here's the code:

QSqlQuery query;
query.prepare(QString("SELECT \
        %1 as nazwa \
        , kontrahentid \
        FROM kontrahent WHERE %2 ilike ?"
    ).arg(showWhat, searchBy) //handled above, no need to escape
);
query.addBindValue(searchString); //user input data - so bind it

if (!query.exec()) {
    qDebug() << query.lastError();
    QApplication::restoreOverrideCursor();
    return;
}

if (model == NULL)
//  model = new QSqlQueryModel; // app closes the window correctly
    model = new QSqlQueryModel(this); // app crashes when closing the window

model->setQuery(query);
if (model->lastError().isValid()) {
    qDebug() << model->lastError();
    QApplication::restoreOverrideCursor();
    return;
}

model->setHeaderData(0, Qt::Horizontal, "ID");
ui.kontrahenciList->setModel(model);
//ui.kontrahenciList->setModelColumn(1);
ui.kontrahenciList->show();

这是我遇到的错误:

Unhandled exception at 0x0fe29f9a (qsqlpsqld.dll) in HurBudClientGUI.exe: 0xC0000005: Access violation reading location 0x00000004.

和调用堆栈:

qsqlpsqld.dll!QScopedPointer<QObjectData,QScopedPointerDeleter<QObjectData> >::data()  Line 143 + 0x3 bytes C++
qsqlpsqld.dll!qGetPtrHelper<QScopedPointer<QObjectData,QScopedPointerDeleter<QObjectData> > >(const QScopedPointer<QObjectData,QScopedPointerDeleter<QObjectData> > & p)  Line 919 + 0xb bytes  C++
qsqlpsqld.dll!QPSQLDriver::d_func()  Line 106 + 0x13 bytes  C++
qsqlpsqld.dll!QPSQLResultPrivate::privDriver()  Line 212    C++
qsqlpsqld.dll!QPSQLResultPrivate::deallocatePreparedStmt()  Line 306 + 0xc bytes    C++
qsqlpsqld.dll!QPSQLResult::~QPSQLResult()  Line 328 C++
qsqlpsqld.dll!QPSQLResult::`scalar deleting destructor'()  + 0xf bytes  C++
Qt5Sqld.dll!QSqlQueryPrivate::~QSqlQueryPrivate()  Line 94 + 0x23 bytes C++
Qt5Sqld.dll!QSqlQueryPrivate::`scalar deleting destructor'()  + 0xf bytes   C++
Qt5Sqld.dll!QSqlQuery::~QSqlQuery()  Line 245 + 0x1e bytes  C++
Qt5Sqld.dll!QSqlQueryModelPrivate::~QSqlQueryModelPrivate()  Line 90 + 0x3d bytes   C++
Qt5Sqld.dll!QSqlQueryModelPrivate::`scalar deleting destructor'()  + 0xf bytes  C++
Qt5Cored.dll!672cbf06()
[Frames below may be incorrect and/or missing, no symbols loaded for Qt5Cored.dll]
Qt5Cored.dll!672cb92a()
Qt5Cored.dll!672c03f4()
Qt5Cored.dll!67200dc4()
Qt5Cored.dll!67203608()
Qt5Sqld.dll!QSqlQueryModel::~QSqlQueryModel()  Line 175 + 0x9 bytes C++

如上所述,当(以下其中一项)时不会发生错误:

As I mentioned above: the error doesn't happen when (one of below):

  • 我创建没有父级的QSqlQueryModel(模型= new QSqlQueryModel;)
  • 我将静态"查询传递给QSqlQueryModel(无论是否具有父查询).

例如:

model->setQuery(
    QSqlQuery(
        QString("SELECT \
            %1 as nazwa \
            , kontrahentid \
            FROM kontrahent"
        ).arg(showWhat)
    )
);

我做错了什么?真正的问题是:QSqlQueryModel拥有父对象的目的是什么?如果我在窗口的析构函数中手动将其删除-有什么区别吗?

What am I doing wrong?And the real question is: what is the purpose for QSqlQueryModel having a parent? If I delete it manually in the window's destructor - is there any diffrence?

我猜这是一个错误-我在qt bugtracker上报告了它: https://bugreports.qt.io/browse/QTBUG-43889

I guess this is a bug - I reported it on qt bugtracker:https://bugreports.qt.io/browse/QTBUG-43889

推荐答案

我想我已经解决了.当模型初始化为视图的子代时:

I guess I solved it. When the model is initialized as view's child:

model = new QSqlQueryModel(this);

问题在于操作顺序.当我关闭连接并在类的析构函数中删除数据库时,数据库将断开连接,无法进行进一步的操作.但是,在我的类的析构函数之后,其基类的析构函数开始起作用-按照继承的顺序一个接一个地起作用.当执行QObject ::〜QObject()时,它会到达

The problem is order of operations. When I close the connection and remove the database in the destructor of my class - the database gets disconnected and no further operations are possible. But after my class' destructor, destructors of its base classes get into action - one by another, as ordered by inheritance. When QObject::~QObject() is executed, it gets to the

QObjectPrivate::deleteChildren()

方法.然后,它最终删除了模型.该模型希望释放资源-这意味着QSqlResult(在这种情况下,QPSQLResult是特定的).这就是它的样子:

method. And then, it finally gets to delete the model. The model wants to free the resources - which means QSqlResult (QPSQLResult to be specific in that case). This it how it looks:

QPSQLResult::~QPSQLResult()
{
    Q_D(QPSQLResult);
    cleanup();
    if (d->preparedQueriesEnabled && !d->preparedStmtId.isNull())
        d->deallocatePreparedStmt();
};

因此,这里Qt尝试取消分配prepareStatement-不管事实如何,该连接不再存在:

So here Qt tries to deallocate preparedStatement - regardless of the fact, that the connection no longer exists:

void QPSQLResultPrivate::deallocatePreparedStmt()
{
    const QString stmt = QLatin1String("DEALLOCATE ") + preparedStmtId;
    PGresult *result = privDriver()->exec(stmt);
    if (PQresultStatus(result) != PGRES_COMMAND_OK)
        qWarning("Unable to free statement: %s", PQerrorMessage(privDriver()->connection));
    PQclear(result);
    preparedStmtId.clear();
};

所以-为了使其正常工作,我不得不打电话

So - to make it work properly, I wolud have to call

QSqlQueryModel::~QSqlQueryModel()

QSqlQueryModel::clear()

在关闭与数据库的连接之前.我仍然认为这是一个错误.

BEFORE closing the connection with the DB. I still think it's a bug.

这篇关于带有父级的QSqlQueryModel-应用程序崩溃的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

07-26 16:11