この章では、dbx による C++ の例外の処理方法と C++ テンプレートのデバッグについて説明します。これらの作業を実行するために使用するコマンドの要約とコード例も示します。
この章の内容は次のとおりです。
C++ プログラムのコンパイルの詳細については、「デバッグのためのプログラムのコンパイル」を参照してください。
この章では C++ デバッグの 2 つの特殊な点を中心に説明しますが、dbx を使用すると、C++ プログラムのデバッグに次の機能を利用することができます。
クラスと型定義の検索 (「型およびクラスの定義を調べる」参照)
継承されたデータメンバーの出力または表示 (「C++ ポインタを出力する」を参照)
オブジェクトポインタに関する動的情報の検索 (「C++ ポインタを出力する」を参照)
仮想関数のデバッグ (「関数を呼び出す」参照)
実行時型情報の使用 (「変数、式または識別子の値を出力する」参照)
クラスのすべてのメンバー関数に対するブレークポイントの設定 (「クラスのすべてのメンバー関数にブレークポイントを設定する」を参照)
多重定義されたすべてのメンバー関数に対するブレークポイントの設定 (「異なるクラスのメンバー関数にブレークポイントを設定する」参照)
多重定義されたすべての非メンバー関数に対するブレークポイントの設定 (「非メンバー関数に複数のブレークポイントを設定する」参照)
特定オブジェクトのすべてのメンバー関数に対するブレークポイントの設定 (「オブジェクトにブレークポイントを設定する」参照)
多重定義された関数またはデータメンバーの処理 (「関数に stop ブレークポイントを設定する」参照)
プログラムは例外が発生すると実行を停止します。例外は、ゼロによる除算や配列のオーバーフローといったプログラムの障害を知らせるものです。ブロックを設定して、コードのどこかほかの場所で起こった式による例外を捕獲できます。
プログラムのデバッグ中、dbx を使用すると次のことが可能になります。
スタックを解放する前に処理されていない例外を捕獲する
予期できない例外を捕獲する
スタックを解放する前に、特定の例外が処理されたかどうかに関係なく捕獲する
特定の例外がプログラム内の特定の位置で起こった場合、それが捕獲される場所を決める
例外処理の発生箇所で step コマンドを実行すると、スタックの開放時に実行された最初のデストラクタの先頭に制御が戻ります。step を実行して、スタックの解放時に実行されたデストラクタを終了すると、制御は次のデストラクタの先頭に移ります。こうしてすべてのデストラクタが終了したあとに step コマンドを実行すると、例外処理の原因を扱う捕獲ブロックに制御が移ります。
exception コマンドでは、デバッグ時にいつでも 例外処理の型を確認できます。オプションなしで exception コマンドを実行するときに表示される型は、dbx 環境変数 output_dynamic_type の設定で制御できます。
この変数を on に設定すると、派生型が表示されます。
この変数を off (デフォルト) に設定すると、静的な型が表示されます。
-d オプションや +d オプションを指定すると、環境変数の設定が無効になります。
-d を設定すると、派生型が表示されます。
+d を設定すると、静的な型が表示されます。
詳細については、「exception コマンド」を参照してください。
スタックを解放する前に、特定の型の例外を阻止または捕獲できます。intercept コマンドを引数を付けずに使用すると、阻止される型がリストで示されます。-all を使用すると、すべての例外が阻止されます。阻止リストに型を追加するには typename を使用します。-x を使用すると、特定の型を除外リストに格納し、阻止から除外することができます。-set を使用すると、阻止リストと除外リストの両方をクリアし、リストを指定した型のみをスローするインターセプトまたは除外に設定できます。
たとえば、int を除くすべての型を阻止するには、次のように入力します。
(dbx) intercept -all -x int |
Error 型の例外を阻止するには、次のように入力します。
(dbx) intercept Error |
CommonError 例外の阻止が多すぎた場合は、次のように入力してその除外を実行することができます。
(dbx) intercept -x CommonError |
intercept コマンド引数なしで入力すると、処理されていない例外および予期で きない例外を含んだ阻止リストが表示されます。これらの例外はデフォルトで阻止され、それに加えてクラス CommonError を除くクラス Error の例外が阻止されます。
(dbx) intercept -unhandled -unexpected class Error -x class CommonError |
Error が例外クラスのものではなく、探している例外クラスの名前が分からない 場合は、次のように入力すると、クラス Error 以外のすべての例外を阻止できます。
(dbx) intercept -all -x Error |
詳細については、「intercept コマンド」を参照してください。
unintercept コマンドは、阻止リストまたは除外リストから例外の型を削除するために使用します。引数を付けずにこのコマンドを使用すると、阻止されている型のリストが示されます (intercept コマンドに同じ)。-all を使用すると、阻止リストからすべての型を削除することができます。typename を使用すると、阻止リストから 1 つの型を削除することができます。-x を使用すると、除外リストから 1 つの型を削除することができます。
詳細については、「unintercept コマンド」を参照してください。
whocatches コマンドは、typename の例外が実行の現時点で送出された場合に、どこで捕獲されるかを報告するものです。このコマンドは、例外がスタックのトップフレームから送出された場合に何が起こるかを検出する場合に使用します。
typename を捕獲した元の送出の行番号、関数名、およびフレーム数が表示されます。捕獲ポイントがスローを行なっている関数と同じ関数内にあると、このコマンドは、「type is unhandled」というメッセージを表示します。
詳細については、「whocatches コマンド」を参照してください。
次の例は、例外を含むサンプルプログラムを使用して、dbx で例外処理がどのように実行されるかを示しています。型 int の例外が、関数 bar で送出されて、次の捕獲ブロックで捕獲されています。
1 #include <stdio.h> 2 3 class c { 4 int x; 5 public: 6 c(int i) { x = i; } 7 ~c() { 8 printf("destructor for c(%d)\n", x); 9 } 10 }; 11 12 void bar() { 13 c c1(3); 14 throw(99); 15 } 16 17 int main() { 18 try { 19 c c2(5); 20 bar(); 21 return 0; 22 } 23 catch (int i) { 24 printf("caught exception %d\n", i); 25 } 26 } |
サンプルプログラムからの次のトランスクリプトは、dbx の例外処理機能を示しています。
(dbx) intercept -unhandled -unexpected (dbx) intercept int <dbx> intercept -unhandled -unexpected int (dbx) stop in bar (2) stop in bar() (dbx)run Running: a.out (process id 304) Stopped in bar at line 13 in file “foo.cc” 13 c c1(3); (dbx) whocatches int int is caught at line 24, in function main (frame number 2) (dbx) whocatches c dbx: no runtime type info for class c (never thrown or caught) (dbx) cont Exception of type int is caught at line 24, in function main (frame number 4) stopped in _exdbg_notify_of_throw at 0xef731494 0xef731494: _exdbg_notify_of_throw : jmp %o7 + 0x8 Current function is bar 14 throw(99); (dbx) step stopped in c::~c at line 8 in file "foo.cc" 8 printf("destructor for c(%d)\n", x); (dbx) step destructor for c(3) stopped in c::~c at line 9 in file "foo.cc" 9 } (dbx) step stopped in c::~c at line 8 in file "foo.cc" 8 printf("destructor for c(%d)\n", x); (dbx) step destructor for c(5) stopped in c::~c at line 9 in file "foo.cc" 9 ) (dbx) step stopped in main at line 24 in file "foo.cc" 24 printf("caught exception %d\n", i); (dbx) step caught exception 99 stopped in main at line 26 in file "foo.cc" 26 } |
dbx は C++ テンプレートをサポートしています。 クラスおよび関数テンプレートを含むプログラムを dbx に読み込み、クラスや関数に使用するテンプレートに対して任意の dbx コマンドを次のように呼び出すことができます。
クラスまたは関数テンプレートのインスタンス化にブレークポイントを設定する (「stop inclass classname コマンド」、「stop infunction name コマンド」、「stop in function コマンド」 参照)
すべてのクラスおよび関数テンプレートのインスタンス化のリストを出力する (「whereis name コマンド」参照)
テンプレートおよびインスタンスの定義を表示する (「whatis name コマンド」参照)
メンバーテンプレート関数と関数テンプレートのインスタンス化を呼び出す (「call function_name( parameters) コマンド」参照)
関数テンプレートのインスタンス化の値を出力する (「print コマンド」参照)
関数テンプレートのインスタンス化のソースコードを表示する (「list コマンド」参照)
次のコード例は、クラステンプレート Array とそのインスタンス化、および関数テンプレート square とそのインスタンス化を示しています。
1 template<class C> void square(C num, C *result) 2 { 3 *result = num * num; 4 } 5 6 template<class T> class Array 7 { 8 public: 9 int getlength(void) 10 { 11 return length; 12 } 13 14 T & operator[](int i) 15 { 16 return array[i]; 17 } 18 19 Array(int l) 20 { 21 length = l; 22 array = new T[length]; 23 } 24 25 ~Array(void) 26 { 27 delete [] array; 28 } 29 30 private: 31 int length; 32 T *array; 33 }; 34 35 int main(void) 36 { 37 int i, j = 3; 38 square(j, &i); 39 40 double d, e = 4.1; 41 square(e, &d); 42 43 Array<int> iarray(5); 44 for (i = 0; i < iarray.getlength(); ++i) 45 { 46 iarray[i] = i; 47 } 48 49 Array<double> darray(5); 50 for (i = 0; i < darray.getlength(); ++i) 51 { 52 darray[i] = i * 2.1; 53 } 54 55 return 0; 56 } |
この例の内容は次のとおりです。
Array はクラステンプレート
square は関数テンプレート
Array<int> はクラステンプレートインスタンス化 (テンプレートクラス)
Array<int>::getlength はテンプレートクラスのメンバー関数
square(int, int*) と square(double, double*) は関数テンプレートのインスタンス化 (テンプレート関数)
次に示すコマンドは、テンプレートおよびインスタンス化されたテンプレートに使用します。クラスまたは型定義がわかったら、値の出力、ソースリストの表示、またはブレークポイントの設定を行うことができます。
whereis コマンドは、関数テンプレートまたはクラステンプレートの、インスタンス化された関数やクラスの出現すべてのリストを出力するために使用します。
クラステンプレートの場合は、次のように入力します。
(dbx) whereis Array member function: `Array<int>::Array(int) member function: `Array<double>::Array(int) class template instance: `Array<int> class template instance: `Array<double> class template: `a.out`template_doc_2.cc`Array |
関数テンプレートの場合は、次のように入力します。
(dbx) whereis square function template instance: `square<int>(__type_0,__type_0*) function template instance: `square<double>(__type_0,__type_0*) |
__type_0 パラメータは、0 番目のパラメータを表します。__type_1 パラメータは、次のパラメータを表します。
詳細については、「whereis コマンド」を参照してください。
関数テンプレートおよびクラステンプレートと、インスタンス化された関数やクラスの定義を出力するために使用します。
クラステンプレートの場合は、次のように入力します。
(dbx) whatis -t Array template<class T> class Array To get the full template declaration, try `whatis -t Array<int>’; |
クラステンプレートの構造については次のように実行します。
(dbx) whatis Array More than one identifier ’Array’. Select one of the following: 0) Cancel 1) Array<int>::Array(int) 2) Array<double>::Array(int> > 1 Array<int>::Array(int 1); |
関数テンプレートの場合は、次のように入力します。
(dbx) whatis square More than one identifier ’square’. Select one of the following: 0) Cancel 1) square<int(__type_0,__type_0*) 2) square<double>(__type_0,__type_0*) > 2 void square<double>(double num, double *result); |
クラステンプレートのインスタンス化の場合は、次のように入力します。
(dbx) whatis -t Array<double> class Array<double>; { public: int Array<double>::getlength() double &Array<double>::operator [](int i); Array<double>::Array<double>(int l); Array<double>::~Array<double>(); private: int length; double *array; }; |
関数テンプレートのインスタンス化の場合は、次のように入力します。
(dbx) whatis square(int, int*) void square(int num, int *result); |
詳細については、「whatis コマンド」を参照してください。
テンプレートクラスのすべてのメンバー関数を停止するには、次のように入力します。
(dbx)stop inclass Array (2) stop inclass Array |
stop inclass コマンドを使用して、特定のテンプレートクラスのメンバー関数すべてにブレークポイントを設定します。
(dbx) stop inclass Array<int> (2) stop inclass Array<int> |
詳細については、「stop コマンド」 と 「inclass classname [-recurse | -norecurse]」を参照してください。
stop infunction コマンドを利用して、指定した関数テンプレートのインスタンスにブレークポイントを設定します。
(dbx) stop infunction square (9) stop infunction square |
詳細については、「stop コマンド」 と 「infunction function」を参照してください。
stop in コマンドを使用して、テンプレートクラスのメンバー関数、またはテンプレート関数にブレークポイントを設定します。
クラスインスタンス化のメンバーの場合は、次のとおりです。
(dbx) stop in Array<int>::Array(int l) (2) stop in Array<int>::Array(int) |
関数インスタンス化の場合は、次のように入力します。
(dbx) stop in square(double, double*) (6) stop in square(double, double*) |
詳細については、「stop コマンド」 と 「in function」を参照してください。
スコープ内で停止した場合に、インスタンス化された関数やクラステンプレートのメンバー関数を明示的に呼び出すには、call コマンドを使用します。dbx で正しいインスタンスを決定できない場合、選択肢となる番号が付いたインスタンスのリストが表示されます。
(dbx) call square(j,&i) |
詳細については、「call コマンド」を参照してください。
print コマンドを使用して、インスタンス化された関数またはクラステンプレートメンバー関数を評価します。
(dbx) print iarray.getlength() iarray.getlength() = 5 |
print を使用して this ポインタを評価します。
(dbx) whatis this class Array<int> *this; (dbx) print *this *this = { length = 5 array = 0x21608 } |
詳細については、「print コマンド」を参照してください。
list コマンドを使用して、指定のインスタンス化された関数のソースリストを出力します。
(dbx) list square(int, int*) |
詳細については、「list コマンド」を参照してください。