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