MochiuWiki : SUSE, EC, PCB
案内
メインページ
最近の更新
おまかせ表示
MediaWiki についてのヘルプ
ツール
リンク元
関連ページの更新状況
特別ページ
ページ情報
We ask for
Donations
検索
個人用ツール
ログイン
Toggle dark mode
名前空間
ページ
議論
表示
閲覧
ソースを閲覧
履歴を表示
Qtの基礎 - 例外処理のソースを表示
提供: MochiuWiki : SUSE, EC, PCB
←
Qtの基礎 - 例外処理
あなたには「このページの編集」を行う権限がありません。理由は以下の通りです:
この操作は、次のグループのいずれかに属する利用者のみが実行できます:
管理者
、new-group。
このページのソースの閲覧やコピーができます。
== 概要 == 例外処理は、プログラムの実行中に発生する予期しないエラーや異常な状況を適切に管理するための重要な機能である。<br> <br> Qtでは、C++の標準例外機構を基本として、Qt独自の拡張が加えられている。<br> <code>try-catch</code>ブロックを使用して、潜在的に例外を投げる可能性のあるコードを囲み、発生した例外を捕捉する。<br> <br> <code>QException</code>クラスは、Qtフレームワーク内で使用される基本的な例外クラスである。<br> このクラスは<code>std::exception</code>を継承しており、Qtに特化した例外を定義するための基盤となっている。<br> <br> 例外を投げる場合は、<code>throw</code>キーワードを使用する。<br> <syntaxhighlight lang="c++"> if (<条件式>) { throw QException(); } </syntaxhighlight> <br> これを捕捉するには、以下に示すように記述する。<br> <syntaxhighlight lang="c++"> try { // 例外が発生する可能性のあるコード } catch (const QException &e) { // QExceptionの処理 } catch (const std::exception &e) { // その他の標準C++例外の処理 } catch (...) { // あらゆる例外の処理 } </syntaxhighlight> <br> <code>QException</code>クラスには、<code>raise</code>メソッドがある。<br> これは、例外を再スローするのに便利であり、例外の連鎖を作成する場合に使用される。<br> <br> また、Qtは、より具体的な例外クラスも提供している。<br> 例えば、<code>QNoMemory</code>等があり、特定のエラー状況に対応している。<br> <br> 例外処理を適切に使用することにより、エラーの発生箇所と処理箇所を分離して、コードの可読性と保守性を向上させることができる。<br> ただし、過度な使用は避け、本当に必要な場合にのみ例外を使用することが推奨される。<br> <br> また、Qtでは例外を完全に無効化することもできる。<br> これは、例外処理のオーバーヘッドを避ける場合や、例外をサポートしていないプラットフォームで開発する場合に有効である。<br> <br><br> == QExceptionクラス == ==== QExceptionクラスとは ==== <code>QException</code>クラスは、スレッド間で転送可能な例外の基底クラスを提供する。<br> <br> <code>QtConcurrent</code>クラスは、<code>QException</code>クラスを継承しており、2つのヘルパー関数を実装することにより、<br> スレッドの境界を越えて例外をスローおよびキャッチすることをサポートする。<br> <code>QException</code>クラスを継承したサブクラスは、値によってスローされ、参照によってキャッチする必要がある。<br> <syntaxhighlight lang="c++"> class SampleException : public QException { public: void raise() const override { throw *this; } SampleException *clone() const override { return new SampleException(*this); } }; </syntaxhighlight> <br> <syntaxhighlight lang="c++"> try { QtConcurrent::blockingMap(list, throwFunction); // throwFunctionはSampleExceptionをスローする関数とする } catch (SampleException &e) { // handle exception // ...略 } </syntaxhighlight> <br> <code>QException</codE>クラスを継承したサブクラスではない例外を投げる場合、Qtの関数は受信側のスレッドで<code>QUnhandledException</code>クラスを投げる。<br> <br> <code>QFuture</code>クラスを使用する場合、以下に示す関数を呼び出すと、転送された例外がスローされる。<br> * QFuture::waitForFinished() * QFuture::result() * QFuture::resultAt() * QFuture::results() <br> ==== QExceptionクラスのメンバ関数 ==== * <code>clone</code>関数 <syntaxhighlight lang="c++"> QException *QException::clone() const </syntaxhighlight> <br> <code>QException</code>クラスを継承したサブクラスにおいて、<code>clone</code>関数を以下のようにオーバーライドする。<br> <syntaxhighlight lang="c++"> SampleException *SampleException::clone() const { return new MyException(*this); } </syntaxhighlight> <br> * <code>raise</code>関数 <syntaxhighlight lang="c++"> void QException::raise() const </syntaxhighlight> <br> <code>QException</code>クラスを継承したサブクラスにおいて、<code>raise</code>関数を以下のようにオーバーライドする。<br> <syntaxhighlight lang="c++"> void MyException::raise() const { throw *this; } </syntaxhighlight> <br><br> == QExceptionの使用例 : 0除算 == 以下の例では、QExceptionクラスを継承して、0除算で例外をスローするクラスを定義している。<br> また、safeDivide関数を定義して、0で除算した場合に、QDivideByZeroExceptionをスローする例を示している。<br> <br> このクラスは、以下に示すような特徴を持つ。<br> * コンストラクタでエラーメッセージを受け取る。 (デフォルトのメッセージもある) * raiseメソッドをオーバーライドして、例外を再スローできる。 * cloneメソッドをオーバーライドして、例外オブジェクトの複製を可能にする。 * whatメソッドをオーバーライドして、エラーメッセージを返す。 <br> <syntaxhighlight lang="c++"> // QDivideByZeroException.hファイル #include <QCoreApplication> #include <QException> class QDivideByZeroException : public QException { private: QString m_message; public: QDivideByZeroException(const QString &message = "ゼロ除算が発生") : m_message(message) {} void raise() const override { throw *this; } QDivideByZeroException *clone() const override { return new QDivideByZeroException(*this); } const char* what() const noexcept override { return m_message.toLocal8Bit().constData(); } }; </syntaxhighlight> <br> <syntaxhighlight lang="c++"> // main.cppファイル #include "QDivideByZeroException.h" double safeDivide(double numerator, double denominator) { if (denominator == 0.0f) { throw QDivideByZeroException("ゼロで除算しようとしました"); } return numerator / denominator; } int main() { try { double result = safeDivide(10.0, 0.0); } catch (const QDivideByZeroException &e) { qDebug() << "Caught exception:" << e.what(); } return 0; } </syntaxhighlight> <br><br> == QExceptionの使用例 : ファイル操作 == 以下の例では、ファイル操作に関連する複数の例外クラスを定義している。<br> <br> * QFileOperationException *: ファイル操作に関する基本的な例外クラス。 * QFileNotFoundException *: ファイルが見つからない場合の例外クラス。 * QFilePermissionException *: ファイルへのアクセス権限がない場合の例外クラス。 <br> これらの例外クラスを使用することにより、ファイル操作時に発生する可能性のある様々なエラーを明確に区別して、適切に処理することができる。<br> readFile関数では、これらの例外を使用してファイルの存在チェックとオープン操作を行っている。<br> ファイルが存在しない場合はQFileNotFoundExceptionクラス、オープンできない場合はQFilePermissionExceptionをスローする。<br> <br> このアプローチには、以下に示すメリットがある。<br> * エラーの種類ごとに異なる処理を行うことができる。 * エラーメッセージをより具体的かつ情報量の多いものにできる。 * コードの可読性と保守性が向上する。 <br> <syntaxhighlight lang="c++"> // QFileOperationException.hファイル #include <QCoreApplication> #include <QFile> #include <QException> #include <QDebug> class QFileOperationException : public QException { protected: QString m_message; public: QFileOperationException(const QString &message) : m_message(message) {} void raise() const override { throw *this; } QFileOperationException *clone() const override { return new QFileOperationException(*this); } const char* what() const noexcept override { return m_message.toLocal8Bit().constData(); } }; class QFileNotFoundException : public QFileOperationException { public: QFileNotFoundException(const QString &fileName) : QFileOperationException(QString("File not found: %1").arg(fileName)) {} }; class QFilePermissionException : public QFileOperationException { public: QFilePermissionException(const QString &fileName) : QFileOperationException(QString("Permission denied: %1").arg(fileName)) {} }; </syntaxhighlight> <br> <syntaxhighlight lang="c++"> // main.cppファイル #include "QFileOperationException.h" // ファイル操作を行う関数 void readFile(const QString &fileName) { QFile file(fileName); if (!file.exists()) { throw QFileNotFoundException(fileName); } if (!file.open(QIODevice::ReadOnly)) { throw QFilePermissionException(fileName); } // ファイルの読み込み処理 qDebug() << "File opened successfully: " << fileName; file.close(); } int main() { try { readFile("nonexistent.txt"); } catch (const QFileNotFoundException &e) { qDebug() << "File not found error:" << e.what(); } catch (const QFilePermissionException &e) { qDebug() << "Permission error:" << e.what(); } catch (const QFileOperationException &e) { qDebug() << "General file operation error:" << e.what(); } catch (const QException &e) { qDebug() << "Unknown Qt exception occurred:" << e.what(); } catch (const std::exception &e) { qDebug() << "Standard exception occurred:" << e.what(); } catch (...) { qDebug() << "Unknown exception occurred"; } return 0; } </syntaxhighlight> <br><br> == 全ての例外をキャッチする方法 == 標準の設定では、NULLポインタのアクセスや0除算等で発生する例外をキャッチすることができない。<br> <syntaxhighlight lang="c++"> char *p = nullptr; try { qDebug() << "try"; *p = 'A'; } catch(...) { qDebug() << "catch"; } </syntaxhighlight> <br> ==== Qtプロジェクトファイル (.pro) の場合 ==== qmakeで生成されたMakefileを見ると、<code>-EHsc</code>オプションが付加されている。<br> <code>/EHs</code>または<code>/EHsc</code>を使用する場合、<code>catch</code>句では、非同期構造化例外がキャッチされない。<br> <br> 構造化例外とは、ハードウェア例外を含むシステム的な例外のことで、<br> Windowsでは、SEH(Structured Exception Handling : 構造化例外処理)という仕組みが提供されている。<br> <br> 全ての例外をキャッチするには、Qtプロジェクトファイル(.pro)に、以下の設定を追記する。<br> <syntaxhighlight lang="make"> win* { QMAKE_CXXFLAGS_EXCEPTIONS_ON = /EHa QMAKE_CXXFLAGS_STL_ON = /EHa } linux* { QMAKE_CXXFLAGS_EXCEPTIONS_ON = /EHa QMAKE_CXXFLAGS_STL_ON = /EHa } </syntaxhighlight> <br> ビルドして生成されたMakefileには、上記で設定した<code>-EHa</code>オプションが付加される。<br> この状態で、上記のサンプルコードを実行すると、例外をキャッチすることができる。<br> <br> ==== CMakeLists.txtファイルの場合 ==== 以下に示す設定を、CMakeLists.txtファイルの適切な位置 (一般的には、プロジェクトとターゲットの設定の後) に追加することにより、<br> プロジェクト全体で全ての例外をキャッチする準備が整う。<br> <br> <syntaxhighlight lang="cmake"> # 例外処理の設定 if(MSVC) # Windows (MSVC)の場合 add_compile_options(/EHa) elseif(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") # GCC または Clang の場合 add_compile_options(-fexceptions) endif() </syntaxhighlight> <br> * Windows(MSVC)の場合 *: <code>/EHa</code>フラグを追加する。 *: これにより、非同期例外を含むすべての例外をキャッチできる。 * Linux (GCC / Clang) の場合 *: <code>-fexceptions</code>フラグを追加する。 *: これにより、例外処理が明示的に有効化される。 <br><br> __FORCETOC__ [[カテゴリ:Qt]]
Qtの基礎 - 例外処理
に戻る。
案内
メインページ
最近の更新
おまかせ表示
MediaWiki についてのヘルプ
ツール
リンク元
関連ページの更新状況
特別ページ
ページ情報
We ask for
Donations
Collapse