Qt4学习笔记 (2)

This is a repost from my previous Qt learning series, based on Qt 4.3.

    之前的笔记: QT4学习笔记 (1). 可以复习一下, 修改了一些错误.
    今天主要说一下Qt的实现, 主要是内存方面. 书上没有写, 完全是自己看源码的, 版本4.3.3 commercial.

    先来还是那段最简单的Qt代码:

    吐了没?= =b.. 还是那个new出来的QLabel的问题, Qt到底怎么样来回收的呢? debug的时候, 我直接把断点设在了QObjectQWidget类的析构函数(直接用debug模式, 打开源码设断点运行就行了). 事实证明还不够. 通过看call stack, 最终发现析构的过程从QApplication这个类开始的.
    /src/gui/kernel/qapplication.cpp, 析构函数中, 有这么一段:

    可能有点难懂, 反正大写Q开头的都是类名. 这段意思大概就是QApplication类会维护一个所有运行中QWidget的mapper, 以便析构函数中作相应处理. 这里似乎只看到调用QWidgetdestory()函数, 没有释放内存. debug的结果也验证了, QLabel的析构函数没有被调用到. 难道Qt不具备防止memory leak的么?
    我们改一下代码, 把heap内存改成stack内存:

    这个显然是没有问题的. 那我们应该怎么用Qt, 才能利用Qt自带的memory管理功能, 只管new, 不用自己delete呢? 再看一段代码:

    (以上sb代码debug之用, 切勿模仿…)
    我们在QDialog上加了一个QLabel, QDialog是在stack上创建的. debug中, 当QDialog对象调用析构函数时, 在/src/gui/kernel/qwidget.cpp中, 会调用QWidget的析构函数. 在QWidget的析构函数中, 有这样一段:

    d是什么东西? 继续跟进, 发现d是一个QObjectPrivate类的对象, 其中的确有delete的操作(废话, 老子依据call stack反推的啊). 于是我们清楚了, Qt的类之间有父子关系(这里指的是包含, 而不是继承关系), 一旦父类对象被被delete的话, 子类也会被相应的delete. 所以, Qt中我们一般都不需要调用delete的. 但是有一个前提: 由于deleteChildren()函数是QObjectPrivate类的函数, 要使以上条件成立的话, 所有的包含关系的类必须都继承自QObject. 这里有一个design pattern, composite, 嗯.
    另外有一点, QObject类没有定义拷贝构造函数, 也就是说一般的赋值都是shadow copy. 其实是有道理的, 当我们copy一个QObject的时候, 新的object到底是继承原来的children还是不继承呢? 呵呵.
    最后我们再来花点时间讨论一下QObjectQObjectPrivate类的关系. 在/src/corelib/global/qglobal.h中, 有以下代码:

    额.. 也就是说, 一般QXxx类和QXxxPrivate类互为friend类, 一般来说QXxxPrivate类都是一些底层实现, 不属于对外的Qt API. 而QXxx类则是对外的Qt API. 有比如说有QProcessQProcessPrivate两个类, 在/src/corelib/io下, 对应4个文件, qprocess.h, qprocess.cpp, qprocess_p.h, qprocess_win.cpp. 前2个是对外的Qt API, *_p.hQProcessPrivate类头文件, *_win.cpp则是对应的平台相关的实现代码.

    好了, 下班了, 明天再写…

Leave a Reply

Your email address will not be published.