分类: LINUX
2013-03-20 10:54:18
在C++中学习过程中,我们都知道:
Qt作为C++的库,显然是不会违背C++的前述原则的。可是:
注:本文暂不涉及智能指针(smart pointer)相关的东西,你可以考虑 Qt 智能指针学习 一文
在Qt中,以下情况下你new出的对象你可以不用 亲自去delete (但你应该清楚delete在何处被Qt调用的,怎么被调用的):
除此之外,有些类的对象可以接收设置一些特别的标记,比如:
注意:这些用法会有些陷阱 ,请注意看本文最后的3个小例子。
在Qt中,最基础和核心的类是:QObject 。它的魔力很大,本文只关注两点:
在Qt中,每个 QObject 内部都有一个list,用来保存所有的 children,还有一个指针,保存自己的parent。当它自己析构时,它会将自己从parent的列表中删除,并且析构掉所有的children。
Q_INVOKABLE QObject::QObject ( QObject * parent = 0 )
QObject::~QObject () [virtual]
void QObject::setParent ( QObject * parent )
注:这三个函数都是通过一个内部私有函数来实现的,这就是
QObjectPrivate::setParent_helper(QObject *o)
每个QObject只有一个父对象:
QObject * QObject::parent () const
子对象可以有多个
const QObjectList & QObject::children () const
所以可以根据条件来查找喽:
T QObject::findChild ( const QString & name = QString() ) const QListQObject::findChildren ( const QString & name = QString() ) const
deleteLater 包含两层意思了
呵呵,似乎这是废话哈。
在去年春节前的时候吧,有人对
obj-> deleteLater()
会像下面一样调用delete:
delete obj;
感到不解。然后我写了这样一个C++例子:
class A { public: A(){} void deleteMe() { delete this; } }; int main() { A * a = new A; a->deleteMe(); return 0; }
应该不需要解释吧
Qt 是事件驱动的,所以发送一个删除事件到事件系统就可以啦:
void QObject::deleteLater() { QCoreApplication::postEvent(this, new QEvent(QEvent::DeferredDelete)); }
事件循环稍后看到该事件就会将其派发会这个widget:
bool QObject::event(QEvent *e) { switch (e->type()) { ... case QEvent::DeferredDelete: ...
很简短、很熟悉的一个例子是不?但是 如果你发现对象的析构函数始终不被成功调用 ,会有什么感觉?
#include#include int main(int argc, char *argv[]) { QApplication app(argc, argv); QLabel *label = new QLabel("Hello Qt!"); label->show(); return app.exec(); }
这是 C++ GUI Programming with Qt 4 一书的第一个例子。我们注意到这儿的 label 既没有指定parent,也没有对其调用delete。
所以,这儿会造成内存泄露。
书中解释说,对于这种小例子,这点内存泄露不算什么。不清楚官方这个例子的意图是什么,或许是一开始就让大家用指针吧。
三种改进方式
QLabel label("Hello Qt!"); label.show();
label->setAttribute(Qt::WA_DeleteOnClose);
int ret = app.exec(); delete label; return ret;
强化一下对前一个例子的了解
#include#include 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对象却不是通过new分配到heap中的。
为了使得用户减少自己显式使用delete,Qt将delete隐藏的比较深。这样一来,不使用new为对象分配空间时,反倒需要多多小心了。
看个小例子:这个程序退出时会直接崩溃 。
#includeint main(int argc, char* argv[]) { QApplication app(argc, argv); QLabel label(tr"Hello Qt!"); QWidget w; label.setParent(&w); w.show(); return app.exec(); }
QLabel label(); delete &label;
QLabel *label = new QLabel("Hello Qt!"); label.setParent(&w)
QWidget w; QLabel label(tr"Hello Qt!");
Qt 对象的父子关系的引入,简化了我们对内存的管理,但是,由于它会在你不太注意的地方调用 delete,所以,使用时还是要当心。