2012-06-14 99 views
2

我們使用Qt 4.8的工作,但老實說,我認爲這有什麼用它做(但我指出來,以防萬一)C++ 4.8運行時堆腐敗

我們創造了這個類,編譯得很好,但崩潰在運行時,出現以下錯誤:

* ERROR: 53:01 Windows已經引發了C_plus_plus_QT_project.exe一個斷點。 這可能是由於堆損壞引起的,這表明C_plus_plus_QT_project.exe或其中已加載的任何DLL錯誤。 這也可能是由於用戶按下F12而C_plus_plus_QT_project.exe有焦點。 輸出窗口可能有更多的診斷信息。*

問題是,QFrame m_FrameHeader;是在.h文件和類構造函數上聲明的我們去做的:

QFrame m_FrameHeader(this); 

我真的很驚訝這個編譯。如果這將是一個測試,任何人都會問我結果會是什麼,我會說這是不會編譯的,因爲重新定義不明確,含糊不清或者沿着這些線。但是,這完全會在運行時發生前面提到的Heap Corruption錯誤時編譯和崩潰。

任何人都可以解釋爲什麼它會編譯,並且當它崩潰時,崩潰而不是堆棧[錯誤]堆崩潰錯誤?爲什麼堆,而不是堆棧?我已經解決了這個問題(它構建成功,運行正常),但我無法解釋爲什麼它會像這樣行爲,而不是我所期望的(編譯錯誤,如果這是錯誤的,我會期望它是一個堆棧錯誤,而不是堆)

我們預計代碼不好,因爲我們現在正在玩Qt,所以我們沒有關注它的質量。請忽略它(除非你認爲它是手頭問題的一部分,那麼請根據需要指出它,哈哈)。

我們的環境:Qt 4.8.2,VS2010,Windows 7 x64。

這是.H

#include <QtGui\QWidget> 
#include <QtGui\QLabel> 
#include <QtGui\QHBoxLayout> 
#include <QtGui\QVBoxLayout> 
#include <QtGui\QGridLayout> 
#include <QtGui\QFrame> 

class Quiniela : public QWidget 
{ 
private: 
    QLabel m_Fecha; 
    QLabel m_Titulo; 
    QLabel m_Hora; 
    QHBoxLayout m_HeaderLayout; 
    QFrame m_FrameHeader; 
    QHBoxLayout m_SorteosLayout; 
    QHBoxLayout m_EntesLayout; 
    QGridLayout m_MainLayout; 
public: 
    Quiniela(int w = 800, int h = 600,QWidget* parent = 0); 
    ~Quiniela(); 
}; 

,這是在.cpp

#include "Quiniela.h" 
#include "FramePrincipal.h" 
#include "Utils.h" 

Quiniela::Quiniela(int w, int h, QWidget * parent) 
    : QWidget(parent) 
{ 
    Utils objUtil; 
    QFont fontHead("Arial", 24, QFont::Black); 
    QFont fontSorteos("Arial", 20, QFont::Normal); 
    resize(w,h); 
    setWindowTitle("QUINIELA"); 
    QFrame m_FrameHeader(this); 
    m_FrameHeader.setGeometry(0,0,800,50); 
    m_Fecha.setText(objUtil.getDate()); 
    m_Fecha.setFont(fontHead); 
    m_Titulo.setText("*** QUINIELA ***"); 
    m_Titulo.setFont(fontHead); 
    m_Hora.setText(objUtil.getTime()); 
    m_Hora.setFont(fontHead); 
    m_HeaderLayout.addWidget(&m_Fecha,0,Qt::AlignLeft); 
    m_HeaderLayout.addWidget(&m_Titulo,0,Qt::AlignCenter); 
    m_HeaderLayout.addWidget(&m_Hora,0,Qt::AlignRight); 
    m_HeaderLayout.setAlignment(Qt::AlignTop); 
    m_FrameHeader.setLayout(&m_HeaderLayout); 
} 

Quiniela::~Quiniela() 
{ 
} 

回答

2

你必須使用Qt的對象的指針(QT通過指針保持親子鏈接,它的對象,並通過父刪除銷燬兒童)。在你的例子中,m_FrameHeader作爲構造函數返回而被銷燬,因爲它被聲明爲局部變量。

1

沒有編譯器錯誤,因爲QFrame m_FrameHeader(this)聲明瞭一個名爲m_FrameHeader的新(本地)變量。這應該從編譯器生成一個警告,你隱藏了相同名稱的類變量。你確定它沒有?無論如何,發生崩潰是因爲一旦構造函數返回,m_FrameHeader就會被銷燬,但它仍然被未被銷燬的東西引用。比如m_HeaderLayout。

+0

謝謝,這是一個非常簡單明瞭的解釋。我會喜歡它,但我沒有聲望。 –

+0

不客氣。 – kenrogers

+0

這是一個誤導性的解釋。發生崩潰不是因爲'm_FrameHeader'被任何東西引用。發生這種情況是因爲'm_FrameHeader'有孩子,並且'刪除'孩子,而且他們沒有單獨分配到堆上。 –

1

您的問題是刪除不直接分配在堆上的對象。

最初,您放在Quiniela類中的小部件是無父母的。

最終您將它們安裝在m_headerLayout佈局中,並且它們將重新設置爲您在其上設置佈局的小部件。

該行m_FrameHeader.setLayout(&m_HeaderLayout)m_Fecha,m_Titulom_Hora的父代設置爲m_FrameHeader

現在請注意m_FrameHeader是一個本地堆棧分配變量,您可以在行QFrame m_FrameHeader(this)中定義該變量。它在Quiniela構造函數的末尾超出範圍。當有孩子的QObject被銷燬時,它會調用所有孩子的delete。然而,這些孩子,特別是m_Fecha,m_Titulom_Hora尚未使用new分配到堆上。

即使您修復了隱藏類成員m_FrameHeader的錯誤,您仍然無法修復崩潰。它只會被推遲到Quiniela的實例被破壞。

解決它的唯一方法是分配堆上的所有小部件。你的小部件應該看起來像這樣:

class Quiniela : public QWidget 
{ 
private: 

    QLabel * m_Fecha; 
    QLabel * m_Titulo; 
    QLabel * m_Hora; 
    QHBoxLayout * m_HeaderLayout; 
    QFrame * m_FrameHeader; 
    QHBoxLayout * m_SorteosLayout; 
    QHBoxLayout * m_EntesLayout; 
    QGridLayout * m_MainLayout; 
    ... 

}; 

你不需要明確地刪除任何這些對象。 Qt會爲你做到這一點,因爲它們最終會被重新安裝到Quiniela小部件實例中。

+0

我知道這篇文章太老了,應該有一個手杖,但是我相信你已經知道,當你說*修復它的唯一方法就是將所有的部件分配到堆上*,這不完全正確。您也可以通過更改類成員的聲明順序來修復它。在父母之前摧毀孩子,它會正常工作。 – thuga

+0

@thuga這是正確的! –