2014-09-04 99 views
0

我對Qt相當新,也許這就是爲什麼我不能完全理解孩子父母的概念。我需要執行一些SQL查詢。我設置了QSqlQuery,執行「準備和綁定」操作並執行它。接下來,我將它傳遞給模型並顯示數據。關閉窗口時發生問題 - 我收到內存違例錯誤。僅當我使用父級創建模型時,纔會出現錯誤。下面的代碼:QSqlQueryModel與父 - 應用程序崩潰

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++ 

正如我上面提到:錯誤不會發生時, (以下之一):

  • 我創建QSqlQueryModel沒有parent(model = new QSqlQueryModel;)
  • 我將「靜態」查詢傳遞給QSqlQueryModel(不管是否有父級)。

如:

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

我在做什麼錯? 真正的問題是:QSqlQueryModel有父級的目的是什麼?如果我在窗口的析構函數中手動刪除它 - 是否有任何差異?

我想這是一個錯誤 - 我報告說,它在QT錯誤追蹤: https://bugreports.qt.io/browse/QTBUG-43889

+1

閱讀關於'Qt's父/子的概念:http://qt-project.org/doc/qt-4.8/objecttrees.html ...你的代碼,你是否刪除了析構函數中的模型? – Zaiborg 2014-09-04 09:09:25

+0

我讀過它......沒有找到對我的情況有用的東西。是的,我在析構函數中手動調用delete(如上一句中提到的) – murison 2014-09-04 09:53:05

+0

這是你的問題。一旦你讓它成爲一個孩子,你無法在任何地方刪除模型。當父母被釋放時,父母會爲你刪除它。 – drescherjm 2014-09-04 12:34:59

回答

0

我想我解決了它。當模型初始化爲視圖的孩子時:

model = new QSqlQueryModel(this); 

問題是操作順序。當我關閉連接並刪除我的類的析構函數中的數據庫時 - 數據庫將斷開連接,並且無法執行其他操作。但是在我的類的析構函數之後,它的基類的析構函數按照繼承的順序一個接一個地執行。當執行QObject ::〜QObject()時,它會得到

QObjectPrivate::deleteChildren() 

方法。然後,它最終刪除模型。該模型想要釋放資源 - 這意味着QSqlResult(QPSQLResult在這種情況下是特定的)。這究竟是怎麼它看起來:

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

所以這裏的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(); 
}; 

所以 - 要使其正常工作,我wolud要叫

QSqlQueryModel::~QSqlQueryModel() 

QSqlQueryModel::clear() 

在關閉與數據庫的連接之前。我仍然認爲這是一個錯誤。

1

這是關鍵部分:

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

在Qt的父子概念提供了許多功能,具有自動兒童破壞是其中之一。

如果任何QObject已將其他QObject設置爲父級,則在刪除父級QObject時,子對象也將被刪除。

現在,你提到你明確地刪除了窗口的析構函數中的model。你不應該。如果您將this定義爲父級,則model將自動與this一起刪除,但它在析構函數中已被您刪除,因此model將被刪除兩次,因此會顯示您的錯誤。

+0

之前發生錯誤 - 在析構函數中添加手動刪除之前... – murison 2014-09-05 12:32:37

0

所以我刪除了析構函數中的「刪除操作」代碼。錯誤仍然存​​在,唯一的區別是不同的調用堆棧。 錯誤消息:

Unhandled exception at 0x0f249f9a (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!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是我的工作類。

相關問題