例外的安全性
予備警告:例外安全は完全な機能ではありません!よくあるケースは動作するはずですが、それでもクラスがリークしたり、クラッシュしたりする可能性があります。
Qt自身は例外をスローしません。代わりにエラーコードが使われます。さらに、QIODevice::errorString() やQSqlQuery::lastError() のように、ユーザーから見えるエラーメッセージを持つクラスもあります。これには歴史的な理由と実用的な理由があります。例外を有効にすると、ライブラリのサイズが20%以上増加します。
以下のセクションでは、コンパイル時に例外サポートを有効にした場合の Qt の動作について説明します。
例外セーフモジュール
コンテナ
Qtのコンテナ・クラスは、一般的に例外に中立です。コンテナ・クラスは、その内部状態を有効に保ちながら、T
、その内部で発生した例外をユーザーに渡します。
例
QList<QString> list; ... try { list.append("hello"); } catch (...) { } // list is safe to use - the exception did not affect it.
このルールの例外は、代入やコピーの構文中にスローする可能性のある型のコンテナです。これらの型では、値を返すだけでなくコンテナを変更する関数も安全ではありません:
MyType s = list.takeAt(2);
s
の代入中に例外が発生した場合、インデックス2の値はすでにコンテナから削除されていますが、s
にはまだ代入されていません。これは回復の見込みなく失われる。
正しい書き方
MyType s = list.at(2); list.removeAt(2);
代入が失敗しても、コンテナには値が残っている。
暗黙的に共有されるQtクラスは、代入演算子やコピーコンストラクタでthrowしないので、上記の制限は適用されないことに注意してください。
メモリ不足の処理
ほとんどのデスクトップOSはメモリをオーバーコミットします。つまり、malloc()
やoperator new
は、割り当て時に十分なメモリがないにもかかわらず、有効なポインタを返します。このようなシステムでは、std::bad_alloc
型の例外はスローされません。
それ以外のオペレーティングシステムでは、割り当てに失敗した場合、Qtはstd::bad_alloc型の例外をスローします。割り当てに失敗するのは、システムがメモリ不足に陥ったり、要求されたサイズを割り当てるのに十分な連続メモリがない場合です。
このルールに対する例外は文書化されている。例として、QImage コンストラクタは、十分なメモリが存在しない場合、例外をスローする代わりにnull イメージを作成します。
例外からの回復
現在のところ、Qt 内で発生した例外(メモリ不足など)から回復するためにサポートされている唯一のユースケースは、イベントループを終了し、アプリケーションを終了する前に何らかのクリーンアップを行うことです。
典型的な使用例です:
QApplication app(argc, argv); ... int ret; try { ret = app.exec(); } catch (const std::bad_alloc &) { // clean up here, e.g. save the session // and close all config files. return EXIT_FAILURE; // exit the application } ... return ret;
例外がスローされた後、ウィンドウサーバーへの接続はすでに閉じられているかもしれません。例外をキャッチした後にGUI関連の関数を呼び出すのは安全ではありません。
クライアント・コードでの例外
シグナルとスロット
Qtのシグナル・スロット接続メカニズムによって呼び出されたスロットから例外をスローすることは、スロット内で処理されない限り、未定義の動作とみなされます:
State state; StateListener stateListener; // OK; the exception is handled before it leaves the slot. QObject::connect(&state, SIGNAL(stateChanged()), &stateListener, SLOT(throwHandledException())); // Undefined behaviour; upon invocation of the slot, the exception will be propagated to the // point of emission, unwinding the stack of the Qt code (which is not guaranteed to be exception safe). QObject::connect(&state, SIGNAL(stateChanged()), &stateListener, SLOT(throwUnhandledException()));
スロットが通常の関数呼び出しのように直接呼び出された場合、例外が使用される可能性があります。これは、スロットを直接呼び出した場合、接続メカニズムがバイパスされるためです:
State state; StateListener stateListener;// ...try{// OK; スロットを直接呼び出す。 qDebug() << "Handling exception not caught in slot."; }
© 2025 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.