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:
我对Qt很陌生,也许这就是为什么我不能完全理解孩子父母的概念。我需要执行一些sql查询。我设置了QSqlQuery,执行“准备和绑定”操作并执行它。接下来,我将它传递给模型并显示数据。当关闭窗口时出现问题—我有内存违规错误。只有当我与父类创建模型时,才会出现错误。这是代码:
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;)
- 我创建的QSqlQueryModel没有父模型(model = new QSqlQueryModel;)
- I pass "static" query to QSqlQueryModel (regardless of having the parent).
- 我将“静态”查询传递给QSqlQueryModel(不考虑是否有父类)。
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?
我做错了什么?真正的问题是:QSqlQueryModel有父类的目的是什么?如果我在窗口的析构函数中手动删除它,有什么不同吗?
I guess this is a bug - I reported it on qt bugtracker: https://bugreports.qt.io/browse/QTBUG-43889
我想这是一个bug——我在qt bugtracker上报告了它:https://bugreports.qt.io/browse/QTBUG-43889。
3 个解决方案
#1
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.
Qt中的父-子概念提供了许多特性,其中之一是自动的子破坏。
If any QObject
has other QObject
set as a parent, then when parent QObject
is deleted, the child object will also be deleted.
如果任何QObject有其他QObject集作为父对象,那么当父QObject被删除时,子对象也将被删除。
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
0
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.
searchDock是我正在学习的课程。
#3
0
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
问题是操作的顺序。当我关闭连接并在类的析构函数中删除数据库时,数据库就会被断开,没有进一步的操作。但是,在我的类“析构函数”之后,它的基类的析构函数会按照继承的顺序依次执行。当QObject::~QObject()被执行时,它会到达。
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:
方法。然后,它最终会删除模型。模型希望释放资源——这意味着QSqlResult(在这种情况下,QPSQLResult是特定的)。这就是它的样子:
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:
所以这里Qt尝试释放preparedStatement——不管事实是什么,连接不再存在:
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.
在关闭与DB的连接之前。我仍然认为这是一个错误。
#1
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.
Qt中的父-子概念提供了许多特性,其中之一是自动的子破坏。
If any QObject
has other QObject
set as a parent, then when parent QObject
is deleted, the child object will also be deleted.
如果任何QObject有其他QObject集作为父对象,那么当父QObject被删除时,子对象也将被删除。
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
0
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.
searchDock是我正在学习的课程。
#3
0
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
问题是操作的顺序。当我关闭连接并在类的析构函数中删除数据库时,数据库就会被断开,没有进一步的操作。但是,在我的类“析构函数”之后,它的基类的析构函数会按照继承的顺序依次执行。当QObject::~QObject()被执行时,它会到达。
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:
方法。然后,它最终会删除模型。模型希望释放资源——这意味着QSqlResult(在这种情况下,QPSQLResult是特定的)。这就是它的样子:
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:
所以这里Qt尝试释放preparedStatement——不管事实是什么,连接不再存在:
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.
在关闭与DB的连接之前。我仍然认为这是一个错误。