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!

  • 4
    点赞
  • 39
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

雨田哥

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值