关于QT的内存申请和释放
进入QT gui 设计的学习也有大半年年了,在做关于QT项目时遇到过关于内存释放错误的问题,曾经一度纠结过!以下是个人关于qt内存管理机制的总结:
首先看一个类:
为了简单起见,我不完成任何功能,只做一个构造函数和一个析构函数。
代码 1.
class MyDialog : public QDialog
{
Q_OBJECT
public:
MyDialog();
~MyDialog();
private:
QHBoxLayout *hLayout;
QVBoxLayout *vLayout ;
QPushButton *btn;
QLineEdit *lineEdit ;
};
代码2.
MyDialog::MyDialog()
:QDialog()
{
btn = new QPushButton("Hello");
lineEdit = new QLineEdit;
hLayout = new QHBoxLayout;
vLayout = new QVBoxLayout ;
hLayout->addWidget(lineEdit);
hLayout->addWidget(btn);
vLayout->addLayout(hLayout1);
setLayout(vLayout) ;
connect(btn,SIGNAL(clicked()),this,SLOT(close()));
}
MyDialog::~MyDialog()
{
delete btn ;
delete lineEdit;
delete hLayout;
delete vLayout ;
}
代码3.
int main(int argc , char ** argv)
{
QApplication app (argc ,argv) ;
MyDialog dlg ;
dlg.show();
return app.exec();
}
代码分析:
从类的声明中,就不难看出,hLayout 、vLayout 、btn 、lineEdit;都是堆结构,就需要我没在 .cpp中实例化一下。
从类的实现部分中,可以看出,好hLayout 布局是放在vLayout中的,按钮和编辑框是放在和Layout中的。
现在看一下析构函数。
经过C语言的学习我们知道,申请的堆空间如果不主动释放,系统不会帮你释放的,所以有new 就要有delete 。
析构函数中,先释放按钮和标签 gui组件,然后释放不可见组件(布局),现在注意了,我们应该先释放好hLayout ,然后在释放Vlayout!
因为hLayout是建立在vLayout上的,如果释放了hLayout 的话,hLayout首先会与vLayout解除关系!
如果在释放的时候,hLayout 与 vLayout 的释放顺序颠倒过来,就会出现段错误,因为先 delete vLayout ,在delete hLayout 的时候,hLayout 将会与vLayout解除关系,但是此时vLayout已经不存在了,所以就会产生段错误。
你些许会有疑问,那为什么btn 和 lineEdit delete的先后顺序可以顺便呢。
这是因为 btn 和 lineEdit 都是可见的Gui组件,delete gui组件时,不需要解除他与布局类的关系。所以顺序就可以随便写了。
总结:
在使用堆结构定义对象的时候,特别是不可见组件,一定要从下往上释放(我说的是相对栈结构),也就是如果,layout1 包含layout2,layout2 包含layout3 ,应该先delete layout3,在layout2,最后layout1 。这样就不容易出错了。
以上说的都是堆结构的,接下来总结一点,关于堆栈混用的。
现在看下面的类:
class MyDialog : public QDialog
{
Q_OBJECT
public:
MyDialog();
~MyDialog();
private:
QHBoxLayout hLayout;
QVBoxLayout vLayout ;
QPushButton *btn;
QLineEdit *lineEdit ;
};
这里我只是把 hLayout 和 vlayout的结构改成了栈结构,而btn 和 lineEdit还是原来的堆结构,构造函数在此就不写出了,逻辑和上面是一样的还是hLayout 放在vlayout中的。
下面是析构函数:
MyDialog::~MyDialog()
{
delete btn ;
delete lineEdit;
}
运行一下代码将会发现,出现了
*** glibc detected *** ./shiyan: double free or corruption (out): 0xbfa0a800 ***
======= Backtrace: =========
/lib/libc.so.6[0xc4bac1]
/lib/libc.so.6(cfree+0x90)[0xc4f0f0]
/usr/lib/libstdc++.so.6(_ZdlPv+0x21)[0x59d96f1]
/usr/lib/libstdc++.so.6(_ZdaPv+0x1d)[0x59d974d]
./shiyan(__gxx_personality_v0+0x357)[0x804a1e3]
./shiyan(__gxx_personality_v0+0x269)[0x804a0f5]
/lib/libc.so.6(__libc_start_main+0xe0)[0xbf8390]
./shiyan(_ZNK7QDialog8sizeHintEv+0x55)[0x8049fd1]
======= Memory map: ========
00110000-00111000 r-xp 00110000 00:00 0 [vdso]
00111000-009c5000 r-xp 00000000 fd:00 3441508 /root/qt/lib/libQtGui.so.4.4.0
009c5000-009e9000 rwxp 008b4000 fd:00 3441508 /root/qt/lib/libQtGui.so.4.4.0
009e9000-009ea000 rwxp 009e9000 00:00 0
009ea000-009ee000 r-xp 00000000 fd:00 1412324 /lib/libgthread-2.0.so.0.1400.2
009ee000-009ef000 rwxp 00003000 fd:00 1412324 /lib/libgthread-2.0.so.0.1400.2
009ef000-009f6000 r-xp 00000000 fd:00 1412323 /lib/librt-2.7.so
乱七八糟的东西,这是为什么呢?
这是因为,栈结构会被系统自动回收,在系统自动释放hLayout和Layout的时候,会把 btn和lineEdit也释放掉,然后自己在写delete btn,delete lineEdit的时候就会出现 double free,因为了把栈结构也释放掉了。
本文允许转载,但请注明出处。
Write by :douyuan888
2013/5/16