2

我们正在使用 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);

老实说,我很惊讶这个编译。如果这将是一个测试并且有人会问我结果是什么,我会说这不会编译,因为变量重新定义、歧义或类似的东西。但这完全会在运行时编译并崩溃,并出现前面提到的堆损坏错误。

谁能解释它为什么会编译,并且当它崩溃时,它会作为堆损坏错误而不是堆栈 [whatever] 错误而崩溃?为什么是堆而不是堆栈?我已经解决了这个问题(它构建正常,运行正常)但我无法解释为什么它的行为是这样而不是我所期望的(编译错误,如果那是错误的,我会期望它是堆栈错误,而不是堆)

我们预计代码会很糟糕,因为我们现在正在玩 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()
{
}
4

3 回答 3

2

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

于 2012-06-14T20:22:13.037 回答
1

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

于 2012-06-14T20:29:23.287 回答
1

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

最初,您放在Quiniela类中的小部件是无父的。

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

该行将和的m_FrameHeader.setLayout(&m_HeaderLayout)父级设置为。m_Fecham_Titulom_Horam_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 小部件实例。

于 2012-06-15T02:48:36.550 回答