C ++ 4.8运行时堆损坏

时间:2012-06-14 20:08:28

标签: c++ qt heap corruption

我们正在使用Qt 4.8,但老实说我相信这与它无关(但是为了以防万一我指出)

我们创建了这个类,它在运行时编译得很好但崩溃时出现以下错误:

* 错误: 53:01 Windows已在C_plus_plus_QT_project.exe中触发了断点。 这可能是由于堆的损坏,这表示C_plus_plus_QT_project.exe或它已加载的任何DLL中的错误。 这也可能是由于用户在C_plus_plus_QT_project.exe具有焦点时按下F12。 输出窗口可能包含更多诊断信息。*

问题在于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()
{
}

3 个答案:

答案 0 :(得分:2)

你必须使用Qt对象的指针(Qt通过指针维护其对象的父子链接,并在父删除时销毁子对象)。在您的示例中,m_FrameHeader在构造函数返回时被销毁,因为它被声明为局部变量。

答案 1 :(得分:1)

没有编译器错误,因为QFrame m_FrameHeader(this)声明了一个名为m_FrameHeader的新(本地)变量。此从编译器生成一条警告,表明您正在隐藏同名的类变量。你确定没有吗?无论如何,崩溃发生是因为一旦构造函数返回就会销毁m_FrameHeader,但仍然会被未被销毁的东西引用。例如m_HeaderLayout。

答案 2 :(得分:1)

您的问题是删除未在堆上直接分配的对象。

最初,您放在Quiniela课程中的小部件是无主义的。

最后,您将它们安装在m_headerLayout布局中,它们将被重新设置为您设置布局的窗口小部件。

m_FrameHeader.setLayout(&m_HeaderLayout)行将父m_Fecham_Titulom_Hora设为m_FrameHeader

现在注意m_FrameHeader是您在行QFrame m_FrameHeader(this)中定义的本地堆栈分配变量。它超出了Quiniela构造函数末尾的范围。当具有子项的QObject被销毁时,它将在所有子项上调用delete。然而,那些孩子,特别是m_Fecham_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小部件实例。