QObject のメモリ管理

まずはサンプルコード

sample.h

#ifndef SAMPLE_H
#define SAMPLE_H
#include <QtCore>

class A : public QObject
{
  Q_OBJECT

  public:
    A(int i_, QObject *parent = NULL) : QObject(parent), i(i_) {}
    virtual ~A() { qDebug("A destructor called"); }
    int value() const { return i; }

  private:
    int i;
};

class B : public QObject
{
  Q_OBJECT
  
  public:
    B(QObject *parent = NULL) : QObject(parent), a(new A(10, this)) {}  //※1
    virtual ~B() { qDebug("B destructor called"); }
    int value() const { return a->value(); }

  private:
    A *a;
};
#endif

sample.cpp

#include "sample.h"

int main(int argc, char *argv[])
{
  QCoreApplication app(argc, argv);
  QPointer<B> b(new B);  //※2
  qDebug("%d", b->value());
  
  return 0;
}

実行結果

$ ./sample
10
B destructor called
A destructor called

解説

※1 QObject の親子関係

このように、QObject (この場合は A) のコンストラクタに他の QObject (この場合は B) のポインタを渡すことによって、
B は A の親(parent)になり、逆に A は B の子(child)になる。
すると、親がデストラクタで破棄されたときに、その後に子のデストラクタも呼ばれて破棄される。
この機構のおかげで、クラスのメンバ変数を破棄するコードをデストラクタにいちいち書かなくていいことになる。

※2 QPoiter クラス

これはいわゆるスマートポインタを提供するクラス。
QObject でないクラスのインスタンスや、トップレベルのインスタンスを保持するのに使えそう。
また、破棄されたときに NULL に設定してくれるため、2回以上 delete しても安全。

便利だね。Qt のコードを書くときは、常に QObject を継承したクラスにしよう。
そうすれば、SIGNALS & SLOTS や QVariant も使えるし。
CUI なプログラムを書くときにも使ってしまいそうだ。