zoukankan      html  css  js  c++  java
  • Qt中delete的问题

    最近项目遇到了一个bug,压力测试ui总会崩溃,gdb调试未果,跑到了库函数,无从查起:

    (gdb)bt

    #0 0x4146b1e4 in QWidgetPrivate::drawWidget(QPaintDevice*, QRegion const&,QPoint const&, int, QPainter*, QWidgetBackingStore*) () from/qt/lib/libQt5Widgets.so.5

    #1 0x4146bb70 in QWidgetPrivate::paintSiblingsRecursive(QPaintDevice*,QList<QObject*> const&, int, QRegion const&, QPoint const&,int, QPainter*, QWidgetBackingStore*) ()

      from /qt/lib/libQt5Widgets.so.5

    #2 0x4146b22c in QWidgetPrivate::drawWidget(QPaintDevice*, QRegion const&,QPoint const&, int, QPainter*, QWidgetBackingStore*) () from/qt/lib/libQt5Widgets.so.5

    #3 0x41443918 in QWidgetBackingStore::sync() () from /qt/lib/libQt5Widgets.so.5

    #4 0x41462c9c in QWidgetPrivate::syncBackingStore() () from/qt/lib/libQt5Widgets.so.5

    #5 0x4146de64 in QWidget::event(QEvent*) () from /qt/lib/libQt5Widgets.so.5

    #6 0x41436a00 in QApplicationPrivate::notify_helper(QObject*, QEvent*) () from/qt/lib/libQt5Widgets.so.5

    #7 0x4143a590 in QApplication::notify(QObject*, QEvent*) () from/qt/lib/libQt5Widgets.so.5

    #8 0x00922918 in ?? ()

    #9 0x00922918 in ?? ()

    Backtracestopped: previous frame identical to this frame (corrupt stack?)

    (gdb)

    后来发现问题是qt中使用delete出错,

            if(p){

               delete p;  // 修改为: p->deletelater();

               p = NULL;// 这里必须置为NULL,否则依然会出错(delete后置空是一个非常好的习惯)

           }

    查阅的参考资料如下:

    http://blog.csdn.net/dbzhang800/article/details/6300025http://my.oschina.net/u/566875/blog/306299

    摘录其中一文片段如下:

    QT有一套回收内存的机制,主要的规则如下:

    1、所有继承自QOBJECT类的类,如果在new的时候指定了父亲,那么它的清理时在父亲被delete的时候delete的,所以如果一个程序中,所有的QOBJECT类都指定了父亲,那么他们是会一级级的在最上面的父亲清理时被清理,而不用自己清理;(注:这里是在new出来对象的时候,这样依靠QObject释放的内存一点问题没有,如果以下这种起情况,那么程序会崩溃。

    QObject derver;
    QObject base;
    derver.setParent(&base);

    儿子和父亲都是栈空间上,释放内存时候,先释放父亲,释放父亲空间的时候,已经把儿子的内存释放了,当释放儿子的内存的是否,会出现内存错误,因为儿子被释放了两次)

    2、程序通常最上层会有一个根的QOBJECT,就是放在setCentralWidget()中的那个QOBJECT,这个QOBJECT在 new的时候不必指定它的父亲,因为这个语句将设定它的父亲为总的QAPPLICATION,当整个QAPPLICATION没有时它就自动清理,所以也无需清理。

    3、如果我们自己释放掉设置QObject为自己父亲的类对象,那个指向的父亲的QObject会从自己的儿子列表中把这个儿子删除掉,就不会出现儿子的内存会被释放两次,如果我们要删除有这种关系的QObject类的话,正常情况,这样它会将这个儿子移出它的列表,并且重新构建显示内容,但是直接这样做时有风险的!

    4、当一个QOBJECT正在接收事件队列时如果中途被你DELETE掉了,就会出现问题了,所以QT中建议大家不要直接DELETE掉一个 QOBJECT,如果一定要这样做,要使用QOBJECT的deleteLater()函数,它会让所有事件都发送完一切处理好后马上清除这片内存,而且就算调用多次的deletelater也不会有问题

    5、QT不建议在一个QOBJECT 的父亲的范围之外持有对这个QOBJECT的指针,因为如果这样外面的指针很可能不会察觉这个QOBJECT被释放,会出现错误,如果一定要这样,就要记住你在哪这样做了,然后抓住那个被你违规使用的QOBJECT的destroyed()信号,当它没有时赶快置零你的外部指针。当然我认为这样做是及其麻烦也不符合高效率编程规范的,所以如果要这样在外部持有QOBJECT的指针,建议使用引用或者用智能指针,如QT就提供了智能指针针对这些情况,见最后一条。

    6、QT中的智能指针封装为QPointer类,所有QOBJECT的子类都可以用这个智能指针来包装,很多用法与普通指针一样

    (某些内存泄露的检测工具会认为QT的程序因为这种方式存在内存泄露,大家不必理会)

    还有一个内存泄漏的问题:

    class ReadoutDisplay : public QWidget
    {
        Q_OBJECT
    public:
    ......
    private:
    
        QGridLayout *m_Gridlayout;
        int m_no_of_rows;
        int m_no_of_col;
    };
    
    ReadoutDisplay::ReadoutDisplay(QWidget *parent, QString type) :
    
        QWidget(parent){
        m_type = type;
        m_Gridlayout = new QGridLayout;
      .......
    }

    泄漏的原因是这里在类中声明的了一个类对象指针,在成员函数中分配了空间,但是没有在成员函数中释放,解决的办法是在析构函数中检查释放:

    ReadoutDisplay::~ReadoutDisplay()
    {
               if(m_Gridlayout)
              {
                  delete m_Gridlayout;
                  m_Gridlayout = NULL;  // once we delete a pointer, it was highly recommended
              }
    }
     转自:http://blog.csdn.net/zzwdkxx/article/details/49804313
     
  • 相关阅读:
    测试1.书店的增删改查项目.链接数据库
    添加约束及打印五角星及查询
    结构
    安装StarUML 及使用时序图(Sequence Diagram)和用例图(use case diagram)
    UMLUnified Modeling Language (UML)又称统一建模语言或标准建模语言
    电视机与遥控器之间的交互
    泛型集合
    狮子和计算Java题
    华为机试——求两个数之间的素数
    判断一个数是否是素数
  • 原文地址:https://www.cnblogs.com/liushui-sky/p/5852014.html
Copyright © 2011-2022 走看看