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を使って管理すると良さそうです。
コメント