質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Qt

QtはGUIプログラムの開発で広く使われているクロスプラットフォーム開発のフレームワークです。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

1回答

7091閲覧

[Qt]Qtと例外は相性が悪いのか?

BeatStar

総合スコア4958

Qt

QtはGUIプログラムの開発で広く使われているクロスプラットフォーム開発のフレームワークです。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

0クリップ

投稿2017/11/04 02:37

編集2017/11/10 08:17

趣味でC++やっています。

Qtについてなのですが、Qtを使うときは例外は投げることができないのでしょうか?

最初、QListWidgetを継承して "リストのアイテムが選択されたら..."等の挙動を指定できるように

QtUse::QtWindow::ListBoxクラス ( QtUse::QtWindow は namespace ) を定義して、

コンストラクタで行う処理を記述したクラスを渡して...という感じでやりました。

で、int QListWidget::getIndex( const QString &text ) というメンバ関数があるとします。

引数として受け取った文字列があるインデックスを返すものです。

このとき、その文字列が QListWidget内にない場合、処理不可能なので std::exceptionを継承した例外クラスを投げました。

すると ランタイムエラーが出ました。

例外を投げなくていい範囲 ( QListWidgetにある文字列 ) にしてみると普通にOK。

情報元は忘れましたが、なんかのサイトで「Qtのスレッド( QThread ) に渡すスレッドから例外を投げるとクラッシュする」というような記事を見た覚えがあります。

Windows APIのスレッド起動も begin_threadでしたっけ? beginが含まれている関数に関数ポインタとして渡すので、

例外が投げられると受け手がいないので例外が補足されず、クラッシュ。

これは理解できます。

なので C由来の方法 ( -1 や 空文字列 等 のようなでたらめな値かどうかをチェックする方法 ) でやるとします。

ここまではまだいいです。

問題はそれ以外の場所から例外を投げる場合です。

QtUse::QtWindow::ListBox等とは別に

CMainクラスを定義します。

サンプルコードとかだと QMainWindowを継承して挙動の定義をするクラスです。

C++

1// IListBoxEventクラスは ListBoxのイベント処理用のインターフェースクラス。 2 3class CMain : IListBoxEvent, 4 /* ... 他にもイベント処理用インターフェースを継承 */ { 5 public: 6 CMain(){ 7 // 生成等 8 } 9 10 ~CMain(){ 11 12 } 13 14 // 関数オブジェクト ( ファンクタ ) にするため。 15 bool opeator()( int argc, char *argv[] ){ 16 init(); 17 18 uinit(); 19 // 他にもあるが... 20 } 21 22 bool buttonClicked(){ 23 24 } 25 26 bool listItemChecked(int index){ 27 28 } 29 30 // 他にもイベント系あり 31 protected: 32 33 bool init( void ){ 34 // ListBox等の生成や設定 35 } 36 37 bool uninit( void ){ 38 // 破棄用 39 } 40 41 ... 42}; 43 44int main( int argc, char *argv[] ){ 45 CMain Main; 46 return Main( argc, argv ); 47}

という風にしています。( 厳密には所々違いますが、サンプルなので。 )

で、このCMainに funcメンバ関数 ( 中身はただ単に例外を投げるだけ )を追加して試してみました。

// これを CMainに追加
void func( void ){
throw -1; // 動くかどうかのテストなのでint型を投げてみた..
}

このfuncメンバ関数を operator()等で例外処理を伴って記述しても

ListBoxのときみたいな Runtime-error が発生します。

Qtには QExceptionという例外クラスがあるようですが、

必ずこれじゃないと無理なのでしょうか?

自分用のライブラリ( CUIでは使えた。例外を投げるクラスや関数がある。 ) を使うことは無理なのでしょうか?

QException ( for Qt ) を使えばいいのかもしれませんが、CUI版はできればその実行ファイルさえあればいいようにしたいので...

( Qtを使うとDLLが多すぎる。 "DLL"ディレクトリを実行ファイルと同じディレクトリにおいてそこに入れる...っていうこともできないし...

( また、std::exception から QExceptionに変更するの大変... メンバが違うし... )

もしQExceptionを使わずに例外を発生させてもOKなやり方があればご教授お願い致します。

[情報]
言語: C++
コンパイラ: MinGW
Qtバージョン: 5.6
QtCreator: 使用しない ( 設定がわけわからん... )

宜しくお願い致します。


追記:

例えば、上記でいえばbuttonClickedメンバ関数 ( メッセージを受け取った際に動かすメンバ ) 内で、

C++

1try{ 2 func(); // 例外が投げられる可能性がある( 今回は必ず投げますが。 )関数 3}catch( int e ){ 4 // ここで表示 5}

としていますが、なぜかクラッシュします。

投げられた例外の型は同じなのに...

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

自分用のライブラリ( CUIでは使えた。例外を投げるクラスや関数がある。 ) を使うことは無理なのでしょうか?

ハンドリングする場所を適切に設計しさえすればどんな例外を発するクラス/関数でも利用できるのではないかと思います。

Qtランタイムのイベントループ |イベント発生 +-------------------->ハンドラー +------>try/catchによるハンドリングの元で +---------->任意の例外が発生する機能を使用 <----------X 例外発生 適切にハンドリングする <--------- <------------------------正常にリターン | |期待外の動作をしたならクラッシュしか選択肢がない ...

この例でいえば「イベントループではハンドラーが常に正常リターンすることを期待し、それ以外はクラッシュ」と設計になっていると思います。ゆえにしかるべき箇所(ここではハンドラーの中のどこか)でtry/catchによる適切なハンドリングをすればよく、それを怠ればクラッシュすることに不思議はないという考えです。

Qtであれなんであれプログラムの構造の中で「この場所ではこの例外はこう扱う」というのが明確に設計されているものだと思います。規定されていない例外を「なんでもかんでもなかったことにする」ような設計は多分しないので「そのようなものが起こったら全てクラッシュ」と考える、つまり「デフォルトはクラッシュ」として捉えるのが妥当ではないでしょうか?


QExceptionについてリファレンスを見ました
http://doc.qt.io/qt-5/qexception.html#details
そこには異なるスレッドから呼び出し元スレッドへ例外を伝播させたい場合はQExceptionが便利ということが書かれてます。QExceptionの派生にしておくと別のスレッドで例外が発生した場合に呼び出し元スレッドへ例外の内容が伝わるので「どんな例外が起こったか」がわかります。一方QExceptionを用いないと「QUnhandledExceptioin」しか受け取れず、呼び出し先スレッドで何が起こったかは何も分かりません。「なんかの例外がおこったらしい」ということしかわからないわけです。

text

1caller thread(A) ------------|------------------ callee thread(B) 2 | | 3 +---------> | 4 try/catch -----> スレッド間呼び出し ----> 5 <-------------- QException スロー 6 例外を(A)スレッドへコピーしてスロー 7 <------------ 8 catch((B)からスローされた例外インスタンスのコピーをcatchできる) 9... 10 +---------> | 11 try/catch -----> スレッド間呼び出し ----> 12 <-------------- QExceptionでないものをスロー 13 例外インスタンスは(A)へコピーできない 14 <------------ 15 catch(QUnhandledException(何が起こったかわからない例外しかcatchできない) 16

単なる推測ですが、QExceptionかどうかと「適切な場所で例外のハンドリングをすべき」ということには直接関係はないと思います。イベントハンドラーでQExceptionをスローしたとき、やはりイベントループでクラッシュする仕様だった・・・となっても驚くにはあたらないと思います。

Qtをよく知らずにコメントしているので間違いがあるかも知れません。その際はご容赦ください。

投稿2017/11/04 05:29

KSwordOfHaste

総合スコア18394

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

BeatStar

2017/11/10 08:11

すみません。遅れました。
BeatStar

2017/11/10 08:13

まだ解決できていませんが、 一応、呼び出し側のところで try~catchをつけて呼び出しているのですが、それでもクラッシュします。 まったく対処しなければクラッシュするのは当然かもしれませんが、 try~catchをつけてもです... ( 本文に追加します。 )
KSwordOfHaste

2017/11/17 03:06

失礼しました。追記されているの気づきませんでした。funcの中でQtのなんらかの機能Fを呼び出していて、その機能からさらに別の関数が起動されているようなケースでFをthrowにより強制的に脱出すると辻褄が合わなくなるといったことは考えられる気がしますが詳細は自分にはわかりかねます。(そういう想像ができるだけです)
BeatStar

2017/11/17 03:16

そうですか。 もうちょっと試してみます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問