C++のスマートポインタの型推論付き初期化 とQPointer

C++ コンピュータ
C++

C++のスマートポインタを学習したのですが、モダンな初期化方法があるとのことですので、試したいと思います。
また、Qt6でGUIプログラミングを学習する予定あり、Qtにもスマートポインタがあり、其の中でQPointerを学習したいと思います。

スマートポインタの型推論付き初期化

#include <iostream>
#include <memory>

using namespace std;

class SampleClass {
public:
    SampleClass() { std::cout << "SampleClass()" << std::endl; }
    ~SampleClass() { std::cout << "~SampleClass()" << std::endl; }
};


int main()
{
    auto ptr = std::make_unique<SampleClass>();
    return 0;
}

/*
出力:
SampleClass()
~SampleClass()
*/

スマートポインタでヒープにインスタンスを生成するコード以下の用になります。

SampleClass* rawPtr = new SampleClass(); // ヒープ上に生成
std::unique_ptr<SampleClass> ptr(rawPtr); // 所有権を unique_ptr に渡す

こちらを1行にまとめると、以下のようなコードになります。

std::unique_ptr<SampleClass> ptr(new SampleClass());

さらに型推論をくわえて、よりモダンな書き方にしたものがサンプルコードの記述方法になります。

auto ptr = std::make_unique<SampleClass>();

QPointer

ファイル名:mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>

QT_BEGIN_NAMESPACE
namespace Ui {
class MainWindow;
}
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow();
    ~MainWindow();

};
#endif // MAINWINDOW_H

ファイル名:mainwindow.cpp

#include <QCoreApplication>
#include <QPointer>
#include <QObject>
#include <QDebug>
#include <QLabel>

#include "mainwindow.h"



MainWindow::MainWindow() {
    // QLabel を生成し、this(ウィンドウ)を親として渡す
    QPointer<QLabel> label = new QLabel("こんにちは、Qt!", this);
    label->setAlignment(Qt::AlignCenter);
    setCentralWidget(label);  // ウィンドウに配置

    // ラベルが有効な間にアクセス可能
    if (label) {
        qDebug() << QString::fromUtf8("ラベルが存在しています:") << label->text();
    }

    // このスコープを抜けても label は生きている(親が保持)
    qDebug() << QString::fromUtf8("QPointer のスコープ終了(まだ生きてるはず)");
}

MainWindow::~MainWindow() {
    qDebug() << QString::fromUtf8("MainWindow が破棄されました");
    qDebug() << QString::fromUtf8("labelもこのタイミングで破棄されるはず。");
    qDebug().noquote() << u8"テスト";
}

ファイル名:main.cpp

#include <QApplication>
#include <QCoreApplication>
#include <QPointer>
#include <QObject>
#include <QDebug>

#include "mainwindow.h"


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

    {
        MainWindow window;
        window.resize(300, 150);
        window.show();

        // イベントループに入る前に明示的に wait(確認用)
        qDebug() << "ウィンドウを表示しました";
        app.exec();
    }

    qDebug() << "main 関数終了(window スコープ外)";
    return 0;
}

実行結果

18:24:09: J:\cpp\QPointer01\build\Desktop_Qt_6_8_2_shared_MinGW_w64_MINGW64_MSYS2-Debug\debug\QPointer01.exe を起動中...
"ラベルが存在しています:" "こんにちは、Qt!"
"QPointer のスコープ終了(まだ生きてるはず)"
ウィンドウを表示しました
"MainWindow が破棄されました"
"labelもこのタイミングで破棄されるはず。"
テスト
main 関数終了(window スコープ外)
18:24:12: J:\cpp\QPointer01\build\Desktop_Qt_6_8_2_shared_MinGW_w64_MINGW64_MSYS2-Debug\debug\QPointer01.exe は終了コード 0 で終了しました

ウィンドウを起動するとラベルが表示されるだけのGUIアプリになります。

ラベル部分のコードでQPointerが使われています。

QPointer<QLabel> label = new QLabel("こんにちは、Qt!", this);

所属するMainWindowオブジェクトが開放されるタイミングでQPointerのオブジェクトも開放されるので、QtのウィジェットはQPointerを使って管理すると良さそうです。

コメント