QSqlQueryModel with a parent - app crash

佐手、 提交于 2019-12-12 02:26:31

问题


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();

Here's the error I'm getting:

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

and the call stack:

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):

  • I create QSqlQueryModel without the parent (model = new QSqlQueryModel;)
  • I pass "static" query to QSqlQueryModel (regardless of having the parent).

eg:

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

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?

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


回答1:


This is the key part:

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

The parent-child concept in Qt provides many features, with automatic child destruction being one of them.

If any QObject has other QObject set as a parent, then when parent QObject is deleted, the child object will also be deleted.

Now, you mentioned you do explicitly delete the model in destructor of the window. You should not. If you define this as a parent, then the model will be automatically deleted together with this, but it was already deleted by you in the destructor, so model is deleted twice, thus your error appears.




回答2:


So I removed the "delete operation" code in the destructor. Error still occurs, the only difference is diffrent call stack. error message:

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

call stack:

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!QScopedPointerDeleter<QObjectData>::cleanup(QObjectData * pointer)  Line 62 + 0x20 bytes   C++
Qt5Cored.dll!QScopedPointer<QObjectData,QScopedPointerDeleter<QObjectData> >::~QScopedPointer<QObjectData,QScopedPointerDeleter<QObjectData> >()  Line 109 + 0x9 bytes  C++
Qt5Cored.dll!QObject::~QObject()  Line 940 + 0x15 bytes C++
Qt5Cored.dll!QAbstractItemModel::~QAbstractItemModel()  Line 1454 + 0xf bytes   C++
Qt5Cored.dll!QAbstractTableModel::~QAbstractTableModel()  Line 3299 + 0x8 bytes C++
Qt5Sqld.dll!QSqlQueryModel::~QSqlQueryModel()  Line 175 + 0x9 bytes C++
HurBudClientGUI.exe!QSqlQueryModel::`scalar deleting destructor'()  + 0x10 bytes    C++
Qt5Cored.dll!QObjectPrivate::deleteChildren()  Line 1841 + 0x24 bytes   C++
Qt5Widgetsd.dll!QWidget::~QWidget()  Line 1488  C++
Qt5Widgetsd.dll!QDockWidget::~QDockWidget()  Line 1172 + 0x22 bytes C++
HurBudClientGUI.exe!searchDock::~searchDock()  Line 28 + 0x1c bytes C++

searchDock is the class I'm working with.




回答3:


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

model = new QSqlQueryModel(this);

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()

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();
};

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()

or

QSqlQueryModel::clear()

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



来源:https://stackoverflow.com/questions/25660089/qsqlquerymodel-with-a-parent-app-crash

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!