您的位置:首页 > 编程语言 > Qt开发

QT之内存泄漏管理

2016-12-13 21:06 337 查看

QT之内存泄漏管理

QT之内存泄漏管理
插叙

QT半自动内存管理

内存例子

内存管理陷阱

QT智能指针

参考链接

结尾

插叙

在C++学习里,我们都知道,New和Delete是成对出现的,如果你忘记了Delete,少了还可以容忍,多了,你就重启应用吧,因为你占用内存太大了

在QT里,我们经常会看到很多NEW出来的对象,但是不需要我们自己去Delete掉。为什么会这样?那是因为QT里,有很多它已经帮我们处理掉了,但是你必须认识到,什么时候QT会帮我清理掉,什么时候却不会。

不是任何时候QT都会帮我们释放掉的,认为QT会帮自己释放掉,结果却造成内存泄漏!内存泄漏!内存泄漏!

QT半自动内存管理

在Qt中,以下情况下你new出的对象你可以不用亲自去delete (但你应该清楚delete在何处被Qt调用的,怎么被调用的):

(1)QObject及其派生类的对象,如果其parent非0,那么其parent析构时会析构该对象。

(2)QWidget及其派生类的对象,可以设置 Qt::WA_DeleteOnClose 标志位(当close时会析构该对象)。

(3)QAbstractAnimation派生类的对象,可以设置 QAbstractAnimation::DeleteWhenStopped。

(4)QRunnable::setAutoDelete()、MediaSource::setAutoDelete()。



注意:这些用法会有些陷阱。

内存例子

(1)

#include <QApplication>
#include <QLabel>

int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QLabel *label = new QLabel("Hello Qt!");
label->show();
return a.exec();
}
//分析:(1)label 既没有指定parent,也没有对其调用delete,所以会造成内存泄漏。


(2)

#include <QApplication>
#include <QLabel>

int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QLabel label("Hello Qt!");
label.show();
return a.exec();
}
//分配对象到栈上而不是堆上


(3)

#include <QApplication>
#include <QLabel>

int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QLabel *label = new QLabel("Hello Qt!");
label->setAttribute(Qt::WA_DeleteOnClose);
label->show();
return a.exec();
}
//设置标志位,close()后会delete label。


(4)

#include <QApplication>
#include <QLabel>

int main(int argc, char *argv[])
{
int ret = 0;
QApplication a(argc, argv);
QLabel *label = new QLabel("Hello Qt!");
label->show();
ret = a.exec();
delete label;
return ret;
}
//new后手动delete


内存管理陷阱

(1)

#include <QApplication>
#include <QLabel>
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QLabel label("Hello Qt!");
label.show();
label.setAttribute(Qt::WA_DeleteOnClose);
return app.exec();
}
//程序崩溃,因为label被close时,delete &label;但label对象是在栈上分配的内存空间,delete栈上的地址会出错。


(2)

#include <QApplication>
#include <QLabel>
int main(int argc, char* argv[])
{
QApplication app(argc, argv);
QLabel label("Hello Qt!");
QWidget w;
label.setParent(&w);
w.show();
return app.exec();
}
//Object内部有一个list,会保存children,还有一个指针保存parent,当自己析构时,会自己从parent列表中删除并且析构所有的children。w比label先被析构,当w被析构时,会删除chilren列表中的对象label,但label是分配到栈上的,因delete栈上的对象而出错。


(3)

#include <QApplication>
#include <QLabel>
int main(int argc, char* argv[])
{
QApplication app(argc, argv);
QWidget *w = new QWidget;
QLabel *label = new QLabel("Hello Qt!");
label->setParent(w);
w->show();
delete w;
label->setText("go");     //野指针
return app.exec();
}
//程序异常结束,delete w时会delete label,label成为野指针,调用label->setText(“Go”);出错。


QT智能指针



(1)QPointer

QPointer是一个模板类。它很类似一个普通的指针,不同之处在于,QPointer 可以监视动态分配空间的对象,并且在对象被 delete 的时候及时更新。

QPointer的现实原理:在QPointer保存了一个QObject的指针,并把这个指针的指针(双指针)交给全局变量管理,而QObject 在销毁时(析构函数,QWidget是通过自己的析构函数的,而不是依赖QObject的)会调用QObjectPrivate::clearGuards 函数来把全局 GuardHash 的那个双指针置为*零,因为是双指针的问题,所以QPointer中指针当然也为零了。用isNull 判断就为空了。

// QPointer 表现类似普通指针
QDate *mydate = new QDate(QDate::currentDate());
QPointer mypointer = mydata;
mydate->year();    // -> 2005
mypointer->year(); // -> 2005

// 当对象 delete 之后,QPointer 会有不同的表现
delete mydate;

if(mydate == NULL)
printf("clean pointer");
else
printf("dangling pointer");
// 输出 dangling pointer

if(mypointer.isNull())
printf("clean pointer");
else
printf("dangling pointer");

// 输出 clean pointer


(2)自动垃圾回收机制

QObjectCleanupHandler :

Qt 对象清理器是实现自动垃圾回收的很重要的一部分。QObjectCleanupHandler可以注册很多子对象,并在自己删除的时候自动删除所有子对象。同时,它也可以识别出是否有子对象被删 除,从而将其从它的子对象列表中删除。这个类可以用于不在同一层次中的类的清理操作,例如,当按钮按下时需要关闭很多窗口,由于窗口的 parent 属性不可能设置为别的窗口的 button,此时使用这个类就会相当方便。

#include <QApplication>
#include <QObjectCleanupHandler>
#include <QPushButton>

int main(int argc, char* argv[])
{
QApplication app(argc, argv);
// 创建实例
QObjectCleanupHandler *cleaner = new QObjectCleanupHandler;
// 创建窗口
QPushButton *w = new QPushButton("Remove Me");
w->show();
// 注册第一个按钮
cleaner->add(w);
// 如果第一个按钮点击之后,删除自身
QObject::connect(w, SIGNAL(clicked()), w, SLOT(deleteLater()));
// 创建第二个按钮,注意,这个按钮没有任何动作
w = new QPushButton("Nothing");
cleaner->add(w);
w->show();
// 创建第三个按钮,删除所有
w = new QPushButton("Remove All");
cleaner->add(w);
QObject::connect(w, SIGNAL(clicked()), cleaner, SLOT(deleteLater()));
w->show();
return app.exec();
}
//在上面的代码中,创建了三个仅有一个按钮的窗口。第一个按钮点击后,会删除掉自己(通过 deleteLater() 槽),此时,cleaner 会自动将其从自己的列表中清除。第三个按钮点击后会删除 cleaner,这样做会同时删除掉所有未关闭的窗口。


参考链接

http://blog.csdn.net/u013711616/article/details/52688581

结尾

只为记录,只为分享! 愿所写能对你有所帮助。Good Good Study, Day Day Up!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: