本章说明了 dbx 如何处理 C++ 异常及调试 C++ 模板,其中概括介绍了完成这些任务所使用的命令,并提供了代码样例示例。
本章由以下部分组成:
有关编译 C++ 程序的信息,请参见编译调试程序。
虽然本章只重点介绍了调试 C++ 的两个特定方面,但您在调试 C++ 程序时可使用 dbx 的全部功能。可以使用的功能包括:
查找类和类型的定义(请参见查找类型和类的定义)
打印或显示继承的数据成员(请参见打印 C++ 指针)
查找有关对象指针的动态信息(请参见打印 C++ 指针)
调试虚函数(请参见调用函数)
使用运行时类型信息(请参见打印变量、表达式或标识符的值)
在类的所有成员函数中设置断点(请参见在类的所有成员函数中设置断点)
在所有重载的成员函数中设置断点(请参见在不同类的成员函数中设置断点)
在所有重载的非成员函数中设置断点(请参见在非成员函数中设置多个断点)
在特定对象的所有成员函数中设置断点(请参见在对象中设置断点)
处理重载函数或数据成员(请参见在函数中设置 stop 断点)
如果出现异常,程序便停止运行。异常会发送编程异常信号,例如:被零除或数组上溢。可以设置块来捕获代码中其他位置的表达式引起的异常。
调试程序时,您可以使用 dbx 完成以下操作:
在堆栈展开之前捕获未处理的异常
捕获意外的异常
在堆栈展开之前捕获已处理或未处理的特定异常
确定程序中特定点处出现的异常的捕获位置
如果在程序停止于异常抛出点后执行 step 命令,则将于堆栈展开期间执行的第一个析构函数的起始处返回控制。如果通过 step 命令步出堆栈展开期间执行的析构函数,则将于下一个析构函数的起始处返回控制。当所有析构函数都执行完毕后,step 命令将前进到处理异常抛出的 catch 块。
在调试期间,可以随时使用 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 命令,则会发现拦截列表中包括未处理的异常和意外的异常(缺省情况下将拦截这些异常),以及 Error 类的异常(CommonError 类的异常除外)。
(dbx) intercept -unhandled -unexpected class Error -x class CommonError |
如果您随后意识到 Error 不是您需要的异常类,但是不知道要查找的异常类的名称,则可以通过键入以下内容来尝试拦截除 Error 类异常之外的所有异常:
(dbx) intercept -all -x Error |
有关更多信息,请参见intercept 命令。
使用 unintercept 命令可从拦截列表或排除列表中删除异常类型。使用不带参数的命令可列出正在拦截的类型(与 intercept 命令相同)。使用 -all 可从拦截列表中删除所有类型。使用 typename 可从拦截列表中删除一个类型。使用 -x 可从排除列表中删除一个类型。
有关更多信息,请参见unintercept 命令。
如果在当前执行点抛出异常,whocatches 命令会报告捕获类型为 typename 的异常的位置。使用此命令可查出自栈的顶帧抛出异常时会发生什么情况。
捕获 typename 的 catch 子句的行号、函数名和帧号均会显示出来。如果捕获点所在函数与抛出异常的函数相同,则该命令返回 "type is unhandled"。
有关更多信息,请参见whocatches 命令。
此示例通过一个包含异常的程序样例说明在 dbx 中如何进行异常处理。在函数 bar 中抛出类型为 int 的异常,并在后面的 catch 块中捕获该异常。
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 命令。
使用 whatis 命令可打印函数模板和类模板的定义以及实例化的函数和类。
对于类模板:
(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 命令。
(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 命令。
(dbx) list square(int, int*) |
有关更多信息,请参见list 命令。