【Qt入門】QWidget::~QWidget()で学ぶオブジェクトの寿命と解放

2025-05-27

QtプログラミングにおけるQWidget::~QWidget()は、QWidgetクラスのデストラクタを意味します。

C++においてデストラクタとは、オブジェクトが破棄される際に自動的に呼び出される特殊なメンバ関数です。オブジェクトがメモリから解放されるとき(スコープを抜ける、deleteされるなど)に、必要なクリーンアップ処理(メモリの解放、リソースのクローズなど)を行うために使用されます。

QWidgetはQtにおけるすべてのユーザーインターフェースオブジェクトの基底クラスです。QWidget::~QWidget()デストラクタの主な役割と特徴は以下の通りです。

  1. 子ウィジェットの自動削除 (Ownership by Parent)
    Qtのオブジェクトモデルでは、QObject(そしてQWidgetQObjectを継承しています)には「親子関係」という概念があります。あるウィジェットが別のウィジェットの「親」として設定されている場合、親ウィジェットが破棄されるときに、そのすべての子ウィジェットも自動的に破棄されます。

    QWidget::~QWidget()が呼び出されると、そのウィジェットに親として設定されているすべての子ウィジェットのデストラクタが自動的に呼び出され、それらのメモリも解放されます。これはQtのメモリ管理において非常に重要な仕組みであり、開発者が手動で多くの子ウィジェットをdeleteする必要がないように設計されています。

  2. リソースの解放
    QWidgetは、表示状態、イベントフィルター、レイアウト、スタイルなど、様々な内部リソースを保持しています。~QWidget()が呼び出されると、これらのリソースが適切に解放されます。

  3. 仮想デストラクタ (Virtual Destructor)
    QWidgetのデストラクタは仮想デストラクタ(virtual ~QWidget())です。これは、QWidgetを継承したクラス(例: QPushButton, QLabel, 自作のカスタムウィジェットなど)のオブジェクトを、基底クラスのポインタ(QWidget*)でdeleteした場合でも、派生クラスのデストラクタが正しく呼び出されることを保証します。これにより、ポリモーフィズムを利用したオブジェクトの正しい破棄が保証されます。

  • 継承されたクラスの正しい破棄を保証するための仮想デストラクタとして機能します。
  • 親ウィジェットが破棄される際に、その子ウィジェットも自動的に破棄されるQtのメモリ管理メカニズムの一部です。
  • ウィジェットが破棄されるときに自動的に実行されるクリーンアップ処理です。


QWidget::~QWidget()関連の一般的なエラーとトラブルシューティング

QWidget::~QWidget()自体が直接エラーメッセージとして現れることは稀ですが、デストラクタが期待通りに動作しない、またはデストラクタが関与するメモリ管理の問題が、アプリケーションのクラッシュや予期せぬ動作として現れることがあります。

"Application has unexpectedly finished." またはクラッシュ

これは最も一般的な問題であり、QWidgetのデストラクタが不適切に呼び出されたり、二重解放などが原因で発生することがあります。

考えられる原因とトラブルシューティング

  • QApplicationが破棄された後のウィジェット操作

    • 原因
      QApplicationオブジェクトが破棄された後に、まだ存在するQWidgetオブジェクトを操作しようとすると、Qtの内部状態が不安定になり、クラッシュを引き起こす可能性があります。

    • main関数でQApplicationをスコープ内に宣言し、そのスコープを抜けた後も、そのQApplicationに関連付けられたウィジェットが残っている場合。
    • トラブルシューティング
      • QApplicationはアプリケーションのライフサイクル全体で存在するようにします。通常、main関数内でQApplicationオブジェクトを作成し、app.exec()を呼び出し、アプリケーションが終了するときにQApplicationも破棄されるようにします。
      • すべてのGUI関連の処理がQApplicationのライフサイクル内に収まるように設計します。
  • 無効なポインタの解放 (Dangling Pointer)

    • 原因
      既に破棄された、または無効なメモリを指しているポインタをdeleteしようとすると発生します。
    • トラブルシューティング
      二重解放と同様に、ポインタの有効性を常に確認し、不要になったオブジェクトのポインタはnullptrに設定するなどの防御的なプログラミングを心がけます。
    • 原因
      既に解放されたQWidgetオブジェクトを再度deleteしようとすると発生します。Qtの親子関係による自動削除の仕組みと、手動でのdeleteが重複している場合によく見られます。

    • QWidget* widget = new QWidget();
      // ...
      delete widget; // 1回目の解放
      // ... (何らかの理由でwidgetへのポインタがまだ有効だと勘違いして)
      delete widget; // 2回目の解放 (クラッシュの原因)
      
      または、親ウィジェットが子ウィジェットを自動的に削除するのに、手動で子ウィジェットをdeleteしてしまう場合。
    • トラブルシューティング
      • Qtのオブジェクトモデル(親子関係)を理解し、親ウィジェットが破棄されるときに子ウィジェットも自動的に削除されることを前提とします。多くの場合、子ウィジェットを明示的にdeleteする必要はありません。
      • deleteを呼び出す前に、ポインタがnullptrでないか確認する、またはdelete後にポインタをnullptrに設定する習慣をつけます。
      • QPointerやスマートポインタ(std::unique_ptr, std::shared_ptrなど)の使用を検討し、メモリ管理をより安全に行うことを検討します。ただし、Qtのオブジェクト(QObjectを継承するクラス)に対しては、Qtの親子関係によるメモリ管理が推奨されます。

メモリリーク (Memory Leak)

QWidget::~QWidget()が期待通りに呼び出されない場合、メモリリークが発生する可能性があります。

考えられる原因とトラブルシューティング

  • カスタムデストラクタでのリソース解放忘れ

    • 原因
      QWidgetを継承した独自のカスタムウィジェットを作成し、その中で動的にメモリを確保したり、ファイルハンドルなどのリソースを開いたりした場合、そのカスタムウィジェットのデストラクタ(~MyCustomWidget())でそれらのリソースを適切に解放し忘れるとメモリリークになります。

    • class MyCustomWidget : public QWidget {
          Q_OBJECT
      public:
          MyCustomWidget(QWidget* parent = nullptr) : QWidget(parent) {
              data = new int[100]; // メモリ確保
          }
          ~MyCustomWidget() {
              // delete[] data; // これを忘れるとメモリリーク
          }
      private:
          int* data;
      };
      
    • トラブルシューティング
      • 動的に確保したリソースは、必ずそのオブジェクトのデストラクタで解放するようにします。
      • RAII (Resource Acquisition Is Initialization) の原則に従い、リソースの取得と解放をオブジェクトのライフサイクルと関連付けるようにします。スマートポインタやQtの提供するリソース管理クラス(例: QFileなど)を活用します。
  • 親子関係が設定されていないウィジェットの破棄忘れ

    • 原因
      new QWidget()で動的にウィジェットを作成したが、親ウィジェットを設定しなかった場合、そのウィジェットは誰にも所有されません。アプリケーションの終了時にdeleteされないとメモリリークになります。

    • MyCustomWidget* widget = new MyCustomWidget(); // 親が設定されていない
      widget->show();
      // アプリケーション終了時にdeleteされないとリーク
      
    • トラブルシューティング
      • 動的に作成するすべてのQObjectおよびQWidget派生クラスには、親を設定するようにします(new MyWidget(parentWidget))。これにより、親が削除されるときに子も自動的に削除されます。
      • 一時的に使用するウィジェットで親を設定しない場合は、使用後に明示的にdeleteを呼び出すか、setAttribute(Qt::WA_DeleteOnClose)を設定します。
      • Qtのシグナル/スロット接続でQt::QueuedConnectionを使用している場合、スロット側のオブジェクトが先に破棄されると、キューされたイベントが処理されずに残り、メモリリークやクラッシュの原因になることがあります。QObject::disconnect()を適切に使用するか、QPointerを使ってスロットのオブジェクトの有効性をチェックします。
  • リンカーエラー (unresolved external symbolなど)

    • 原因
      QWidgetクラスを使用しているにもかかわらず、QtのGUIモジュール(Qt 5ではQtWidgets)がプロジェクトに正しくリンクされていない場合に発生します。
    • トラブルシューティング
      .proファイルにQT += widgetsを追加し、qmakeを実行してプロジェクトファイルを再生成します。Qt Creatorを使用している場合は、プロジェクト設定で必要なモジュールが有効になっていることを確認します。
  • QWidget: Must construct a QApplication before a QPaintDevice

    • 原因
      QApplicationオブジェクトが作成される前にQWidget(またはQPaintDeviceを継承するクラス)を作成しようとすると発生します。QtのGUI機能はQApplicationが初期化されることで初めて利用可能になります。
    • トラブルシューティング
      main関数の冒頭でQApplication app(argc, argv);のように、必ず最初にQApplicationのインスタンスを作成します。
  • Qtドキュメントの参照
    Qtの公式ドキュメントは非常に充実しています。特にQWidgetクラスのドキュメントや、メモリ管理に関するセクションを確認することで、設計上の誤りを発見できることがあります。
  • 最小限の再現コード
    問題が発生した場合、その問題を再現できる最小限のコードを作成してみます。これにより、複雑なプロジェクトの中から問題の切り分けを行うことができます。
  • Valgrindなどのメモリデバッグツール
    Linux環境であればValgrindのようなツールを使用することで、メモリリークや無効なメモリアクセスを詳細に検出できます。
  • Qt Debugging Aids
    QtにはqDebug(), qWarning(), qCritical(), qFatal()などのデバッグ出力関数があります。これらを活用して、オブジェクトの生成・破棄のタイミングや、ポインタの有効性をログに出力することで、問題の発見に役立ちます。
  • デバッガの使用
    メモリ関連の問題(クラッシュ、二重解放など)は、デバッガを使用してコールスタックを確認することで原因を特定しやすいです。どの関数がクラッシュを引き起こしているのか、その前の呼び出し履歴はどうなっているのかを追跡します。


例1: 親子関係による自動削除(最も一般的)

Qtのメモリ管理の最も基本的な例です。親ウィジェットが破棄されると、その子ウィジェットも自動的に破棄されます。ここでQLabelのデストラクタが自動的に呼び出されます。

// main.cpp
#include <QApplication>
#include <QWidget>
#include <QLabel>
#include <QVBoxLayout>
#include <QDebug> // デバッグ出力用

// カスタムウィジェットでデストラクタの呼び出しを確認
class MyChildWidget : public QWidget
{
    Q_OBJECT // QObjectを継承しているので必要
public:
    MyChildWidget(const QString& name, QWidget* parent = nullptr)
        : QWidget(parent), m_name(name)
    {
        qDebug() << "MyChildWidget" << m_name << "created.";
        // レイアウトとラベルを追加
        QVBoxLayout* layout = new QVBoxLayout(this);
        QLabel* label = new QLabel("Hello from " + m_name, this);
        layout->addWidget(label);
    }

    ~MyChildWidget() override // デストラクタ
    {
        qDebug() << "MyChildWidget" << m_name << "destroyed.";
    }

private:
    QString m_name;
};

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    qDebug() << "Main window creation scope started.";

    // メインウィンドウを作成(スタックに確保)
    // スコープを抜けるときに自動的に破棄される
    {
        QWidget mainWindow; // メインウィンドウをスタックに確保
        mainWindow.setWindowTitle("Parent Widget Example");
        mainWindow.resize(300, 200);

        QVBoxLayout* mainLayout = new QVBoxLayout(&mainWindow);

        // 子ウィジェットを作成し、親をmainWindowに設定
        MyChildWidget* child1 = new MyChildWidget("Child A", &mainWindow);
        MyChildWidget* child2 = new MyChildWidget("Child B", &mainWindow);

        mainLayout->addWidget(child1);
        mainLayout->addWidget(child2);

        mainWindow.show();

        qDebug() << "Main window creation scope finished. Entering exec().";

        // この時点でmainWindowとその子ウィジェットはメモリに存在
        // app.exec()が終了し、mainWindowのスコープを抜けるとデストラクタが呼ばれる
        return a.exec();
    } // mainWindowのスコープがここで終了。~QWidget()が呼ばれる。

    qDebug() << "Application finished."; // このメッセージは通常表示されない(return a.exec()で終了するため)
    // プログラムが完全に終了する際、QApplicationオブジェクトも破棄される
}

#include "main.moc" // mocファイルを含める(MyChildWidgetにQ_OBJECTがあるため)

解説

  1. MyChildWidgetクラスには、コンストラクタとデストラクタでデバッグメッセージを出力するようにしています。
  2. main関数内でQWidget mainWindow;とスタックにメインウィンドウを作成しています。
  3. new MyChildWidget("Child A", &mainWindow);のように、子ウィジェットを作成する際に親ウィジェットとして&mainWindowを渡しています。
  4. a.exec()が終了し、mainWindowのスコープ({ ... }ブロック)を抜けると、mainWindowのデストラクタであるQWidget::~QWidget()が自動的に呼び出されます。
  5. mainWindowのデストラクタが呼び出されると、Qtの親子関係の仕組みにより、child1child2のデストラクタであるMyChildWidget::~MyChildWidget()も自動的に呼び出され、これらの子ウィジェットが適切にメモリから解放されます。

実行結果の例

Main window creation scope started.
MyChildWidget Child A created.
MyChildWidget Child B created.
Main window creation scope finished. Entering exec().
// ... (GUIが表示され、ユーザーがウィンドウを閉じると)
MyChildWidget Child A destroyed.
MyChildWidget Child B destroyed.

この出力から、親ウィジェットのスコープが終了する際に子ウィジェットが自動的に破棄されていることが分かります。

例2: deleteLater() の使用

deleteLater()は、ウィジェットをすぐに削除するのではなく、現在のイベントループの処理が完了した後に削除をキューに入れる安全な方法です。これは、スロットがまだ実行中のウィジェットをdeleteしようとするような、タイミングの問題を避けるのに役立ちます。

// main.cpp
#include <QApplication>
#include <QPushButton>
#include <QVBoxLayout>
#include <QDebug>

class MyTemporaryWidget : public QWidget
{
    Q_OBJECT
public:
    MyTemporaryWidget(QWidget* parent = nullptr) : QWidget(parent)
    {
        qDebug() << "MyTemporaryWidget created.";
        QVBoxLayout* layout = new QVBoxLayout(this);
        QPushButton* closeButton = new QPushButton("Close Me", this);
        layout->addWidget(closeButton);

        // ボタンがクリックされたら、自分自身をイベントループの後に削除する
        connect(closeButton, &QPushButton::clicked, this, &MyTemporaryWidget::requestDelete);
    }

    ~MyTemporaryWidget() override
    {
        qDebug() << "MyTemporaryWidget destroyed.";
    }

public slots:
    void requestDelete()
    {
        qDebug() << "requestDelete() called. Scheduling deletion...";
        this->deleteLater(); // 自分自身をイベントループの後に削除するようにスケジュール
    }
};

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    QWidget mainWindow;
    mainWindow.setWindowTitle("Delete Later Example");
    mainWindow.resize(300, 100);

    QVBoxLayout* mainLayout = new QVBoxLayout(&mainWindow);
    QPushButton* createButton = new QPushButton("Create Temporary Widget", &mainWindow);
    mainLayout->addWidget(createButton);

    mainWindow.show();

    // ボタンがクリックされたら新しい一時ウィジェットを作成
    QObject::connect(createButton, &QPushButton::clicked, [&]() {
        MyTemporaryWidget* tempWidget = new MyTemporaryWidget(&mainWindow); // 親を設定
        tempWidget->show();
        tempWidget->setWindowTitle("Temporary Window");
    });

    return a.exec();
}

#include "main.moc"

解説

  1. MyTemporaryWidgetは、ボタンがクリックされるとrequestDelete()スロットを呼び出します。
  2. requestDelete()内でthis->deleteLater();が呼び出されます。
  3. deleteLater()は、すぐに~MyTemporaryWidget()を呼び出すのではなく、Qtのイベントループが現在の処理を終えた後でデストラクタが呼び出されるようにスケジュールします。これにより、デストラクタの呼び出し中に発生しうる問題を回避できます。
  4. この例では、MyTemporaryWidgetmainWindowの子として作成されていますが、deleteLater()を使うことで、親が破棄されるのを待たずに明示的に(しかし安全に)自身のライフサイクルを管理できます。

実行結果の例

  1. アプリケーションを実行し、"Create Temporary Widget"ボタンをクリック。
    • MyTemporaryWidget created. と表示され、新しい一時ウィンドウが開く。
  2. 一時ウィンドウの"Close Me"ボタンをクリック。
    • requestDelete() called. Scheduling deletion... と表示。
  3. 一時ウィンドウが閉じられ(隠され)、しばらくして(イベントループがアイドル状態になった後)
    • MyTemporaryWidget destroyed. と表示。

これはQWidgetのデストラクタそのものというより、QWidgetを継承したクラスで、動的に確保した追加リソースを適切に解放する方法です。

// main.cpp
#include <QApplication>
#include <QWidget>
#include <QVBoxLayout>
#include <QLabel>
#include <QDebug>
#include <QFile> // ファイル操作用

class MyResourceWidget : public QWidget
{
    Q_OBJECT
public:
    MyResourceWidget(QWidget* parent = nullptr) : QWidget(parent)
    {
        qDebug() << "MyResourceWidget created.";
        QVBoxLayout* layout = new QVBoxLayout(this);
        QLabel* label = new QLabel("Widget with Custom Resources", this);
        layout->addWidget(label);

        // シミュレートされたリソースの確保
        m_data = new int[100]; // 動的なメモリ確保
        qDebug() << "Allocated 100 ints.";

        m_file = new QFile("temp_log.txt", this); // ファイルオブジェクトの作成
        if (m_file->open(QIODevice::WriteOnly | QIODevice::Text)) {
            m_file->write("Log started.\n");
            qDebug() << "Opened temp_log.txt";
        }
    }

    ~MyResourceWidget() override
    {
        qDebug() << "MyResourceWidget destroyed.";

        // 確保したリソースの解放
        if (m_data) {
            delete[] m_data; // 動的に確保した配列を解放
            m_data = nullptr;
            qDebug() << "Freed 100 ints.";
        }

        // QFileはQObjectの子であるため、親を設定していれば自動的に解放される
        // ただし、明示的にクローズしておくのは良い習慣
        if (m_file && m_file->isOpen()) {
            m_file->close();
            qDebug() << "Closed temp_log.txt";
        }
        // m_file自体もQObjectの子なので、親が設定されていればdeleteの必要はない
        // delete m_file; // 通常は不要。親が解放してくれる。
    }

private:
    int* m_data = nullptr; // 動的に確保するデータ
    QFile* m_file = nullptr; // 開いたファイルオブジェクト
};

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    {
        MyResourceWidget resourceWidget; // スタックに確保
        resourceWidget.setWindowTitle("Resource Widget");
        resourceWidget.resize(400, 150);
        resourceWidget.show();

        return a.exec();
    } // resourceWidgetのスコープ終了、デストラクタが呼ばれる
}

#include "main.moc"

解説

  1. MyResourceWidgetクラスは、コンストラクタでnew int[100]でメモリを確保し、QFileオブジェクトを作成してファイルを開いています。
  2. ~MyResourceWidget()デストラクタでは、コンストラクタで確保したm_data配列をdelete[] m_data;で解放しています。
  3. QFileオブジェクトm_fileMyResourceWidgetを親として作成されているため、MyResourceWidgetが破棄されるときに自動的にm_fileも破棄されます。しかし、ファイルハンドル自体は明示的にm_file->close()でクローズしておくのが良い習慣です。

実行結果の例

MyResourceWidget created.
Allocated 100 ints.
Opened temp_log.txt
// ... (GUIが表示され、ユーザーがウィンドウを閉じると)
MyResourceWidget destroyed.
Freed 100 ints.
Closed temp_log.txt

この出力から、ウィジェットが破棄される際に、コンストラクタで確保したカスタムリソースもデストラクタによって適切に解放されていることが分かります。



QtにおけるQWidget::~QWidget()(デストラクタ)は、Qtのオブジェクトモデルにおけるメモリ管理の根幹をなすものであり、直接的な代替手段という概念はあまりありません。デストラクタはC++言語の機能であり、オブジェクトのライフサイクルが終了する際に自動的に呼び出されるものです。

しかし、「QWidget::~QWidget()が呼び出される状況(つまり、ウィジェットが破棄される状況)」をプログラマがどのようにコントロールするか、またはデストラクタに依存せずにリソースを解放する他の方法があるか、という視点で見ると、いくつかの関連するプログラミング手法や概念があります。

Qtの親子関係による自動メモリ管理(最も推奨される方法)

これはQWidget::~QWidget()が最も効果的に機能する状況であり、**「代替」というよりも「活用方法」**です。

  • デメリット
    • 親子関係の概念を理解していないと、意図しないタイミングでオブジェクトが破棄されたり、逆に破棄されなかったりする可能性がある。
  • メリット
    • メモリ管理が非常にシンプルになる。
    • 多くのメモリリークや二重解放を防ぐことができる。
    • Qtアプリケーションの標準的なパターン。
  • コード例
    // MyWidgetはparentWindowの子として作成される
    MyWidget* myWidget = new MyWidget(parentWindow);
    // parentWindowが破棄されると、myWidgetも自動的に破棄され、~MyWidget()が呼ばれる
    
  • 説明
    QObject(そしてQWidget)は、親オブジェクトを設定することで、その親が破棄されるときに子オブジェクトも自動的に破棄される仕組みを持っています。これにより、開発者は手動で子ウィジェットをdeleteする手間を省き、メモリリークのリスクを減らすことができます。

QObject::deleteLater()

これは「今すぐデストラクタを呼び出す」のではなく、「イベントループの次のサイクルでデストラクタを呼び出すようにスケジュールする」方法です。

  • デメリット
    • 即座にメモリが解放されるわけではないため、リソースがすぐに必要ない場合にのみ適している。
    • イベントループがない環境では機能しない。
  • メリット
    • 実行中のコードの安全性を確保しつつ、オブジェクトを削除できる。
    • デッドロックやクラッシュを防ぐのに役立つ。
  • コード例
    connect(myButton, &QPushButton::clicked, myWidget, &QWidget::deleteLater);
    // myButtonがクリックされると、myWidgetの~QWidget()がイベントループの後に呼ばれる
    
  • 説明
    ウィジェットが何らかのイベント(例えばボタンクリック)によって自分自身を削除したいが、そのイベント処理中に自身が削除されると問題が発生する可能性がある場合(例:まだアクセスする必要があるメンバー変数がある場合)に非常に有用です。deleteLater()を呼び出すと、QObjectのデストラクタが安全なタイミングで呼び出されます。

setAttribute(Qt::WA_DeleteOnClose)

これは、トップレベルのウィジェット(ウィンドウ)に適用される特殊な属性です。

  • デメリット
    • 子ウィジェットには適用されない(親ウィジェットが閉じても、その子ウィジェットがこの属性を持つとは限らない)。
    • ウィジェットが閉じられない限り削除されない。
  • メリット
    • ダイアログや一時的なウィンドウのメモリ管理が簡単になる。
  • コード例
    MyDialog* dialog = new MyDialog();
    dialog->setAttribute(Qt::WA_DeleteOnClose); // ダイアログが閉じられたら自動的に削除
    dialog->show();
    
  • 説明
    ウィジェットが閉じられたときに自動的に削除されるように設定します。通常、QWidgetclose()メソッドが呼び出されたときにデストラクタが呼び出されます。これは特にダイアログや独立したウィンドウで便利です。

スマートポインタ(C++11以降のstd::unique_ptr, std::shared_ptrなど)

Qtのオブジェクトモデルと組み合わせる際には注意が必要ですが、Qt以外のリソース管理には非常に強力です。

  • デメリット
    • QObjectの子孫であるQtオブジェクト(QWidgetを含む)を直接管理するのには不向き。Qtの親子関係の仕組みが優先されるべき。
  • メリット
    • 手動でのdelete忘れによるメモリリークを防ぐ。
    • 例外安全性を提供する(例外が発生してもリソースが解放される)。
    • C++標準ライブラリの一部であり、Qtに依存しない。
  • コード例(QWidget内部でのリソース管理)
    class MyWidgetWithResource : public QWidget {
        Q_OBJECT
    public:
        MyWidgetWithResource(QWidget* parent = nullptr) : QWidget(parent) {
            my_data = std::make_unique<MyLargeDataStructure>(); // スマートポインタでデータ確保
        }
        // デストラクタで明示的にdeleteする必要はない。
        // ~MyWidgetWithResource() override {
        //     // my_dataはスコープを抜けるときに自動的に解放される
        // }
    private:
        std::unique_ptr<MyLargeDataStructure> my_data;
    };
    
  • 説明
    スマートポインタは、動的に確保されたオブジェクトの寿命を管理し、スコープを抜けるときに自動的にdeleteを呼び出してくれるポインタです。QWidgetオブジェクト自体をスマートポインタで管理することはQtの親子関係によるメモリ管理と競合する可能性があるため推奨されませんが、QWidgetの内部で動的に確保したQt以外のリソース(例:std::vector、カスタムデータ構造など)の管理には非常に適しています。

QWidget::~QWidget()自体は、オブジェクトが破棄されるときに呼び出されるC++の基本的な仕組みです。その「代替」というよりも、Qtではそのデストラクタがいつ、どのように呼び出されるかを制御するための様々な便利な方法が提供されています。

  • スマートポインタ
    QWidgetの内部で、Qtのオブジェクトモデルに属さないカスタムリソースの寿命管理に用いる。
  • setAttribute(Qt::WA_DeleteOnClose)
    ウィンドウが閉じられたときに自動的にデストラクタを呼び出す。
  • deleteLater()
    イベントループの後に安全にデストラクタを呼び出す。
  • Qtの親子関係
    最も重要で推奨される方法。親が破棄されると子が自動的に破棄される。