赞
踩
上一篇文章说了对于一组有继承关系的异常类,catch块的顺序。现在说下其他情况下的顺序。
确实有这种情况存在。比如你写了一个函数,调用了别人写的一个函数,你不清楚别人的这个函数可能会引发什么异常。
这时候,可以在catch的括号中写省略号,表示任何异常类型,就可以捕捉任何类型的异常。
catch (```)
{
···
}
可以把自己知道的可能的异常写在前面,然后把省略号表示的任何类型的异常写在最后,就像switch语句的default语句一样嘚。当然前面那些异常如果有继承关系,也要按照祖先类在后孩子类在前的顺序。
try{
duper();
}
catch (bad_3 & be){
···
}
catch (bad_2 & be){
···
}
catch (bad_1 & be){
···
}
catch(```){//catch whatever is left
···
}
即按值传递。当然啦,传回来的只是throw的对象的副本,因为按值传递嘛。
那么捕获到的就是对象的副本,不再是对象的副本的引用,这时候,如果catch参数是基类对象,则所有派生类的对象仍然会被捕捉,但是却不再可以派生,所以catch块内只能使用虚方法的基类版本,而没办法使用派生类自己的版本。
引用真是有用,原来按引用传递才能维持继承关系。
C++的库定义了很多从exception类派生来的异常类。这些类的名称指出了他们报告的错误类型。
这个头文件定义了从exception类公有派生来的logic_error
类和runtime_error
类。这两个类成为了两大派生类系列的基类。即异常类大致分为两大派系,分别由logic_error
类和runtime_error
类派生出去。
如果这两个类以及他们派生的类还是没办法解决你的问题,你可以自己从logic_error
类和runtime_error
类中派生一个异常类,自己来写。从他俩中派生是为了保证你的异常也在继承层次中,catch块的顺序好放。
可以看到,这几个类的构造函数都接受一个string引用参数。
logic_error
类:描述典型的逻辑错误,这类错误可以通过编程修复从logic_error
类派生出来的异常类有:
domain_error
类:domain,是定义域的意思。range表示值域。我试了试
cout << std::asin(2);
应该是引发了异常,异常被捕捉到,catch块的操作是返回非数值。只不过没有打印有关异常的任何信息而已,实际上asin函数的库版本一定是用了异常处理的。
nan
invalid_argument
类: 传递的参数无效,比如函数只要0或1,你传2,就会引发。length_error
类:没有足够空间就会引发。比如,string类的append方法,合并两个string对象时,得到的串的长度如果超出了最大允许长度(?),就会引发。out_of_bounds
类:指示索引错误。比如数组下标不对。这些错误,平时也多多少少都见过。
runtime_error
类:这类异常是无法避免的问题从runtime_error
类派生出来的异常类有:
overflow_error
:当整型和浮点型的计算结果超出自己类型能表示的最大范围时候,就会引发上溢异常。underflow_error
类:只发生在浮点数的计算中,整型不会遇到这个问题。计算结果比浮点类型能够表示的最小非零值还要小的时候,就会引发。range_error
类:计算结果没有上溢也没下溢,但是不在函数允许的范围内,就引发。C语言malloc函数,以及C++以前的new运算符,分配内存失败返回一个空指针,后来C++改用异常处理,C还是返回空指针。
//main.cpp #include <iostream> #include <string> #include <new> #include <cstdlib> //exit()函数 struct Big{ double stuff[20000]; }; int main() { Big * p; try{ p = new Big[10000];//1.6GB std::cout << "Got past the new request: \n"; } catch (std::bad_alloc & ba){ std::cout << "Caught the exception!\n"; std::cout << ba.what() << std::endl; exit(EXIT_FAILURE); } std::cout << "Memory successfully allocated!\n"; p[0].stuff[0] = 4; std::cout << p[0].stuff[0] << std::endl; delete [] p; return 0; }
Got past the new request:
Memory successfully allocated!
4
double stuff[20000];
Caught the exception!
std::bad_array_new_length
Process returned 1 (0x1) execution time : 0.337 s
Press any key to continue.
我和书上返回的字符串不一样啊。
书上还说,为了和以前的空指针方案兼容,毕竟有很多代码已经那么写了。于是C++标准提供了一个开关,让用户来选择到底用哪一种方案。
代码:
//main.cpp #include <iostream> #include <string> #include <new> #include <cstdlib> //exit()函数 struct Big{ double stuff[20000]; }; int main() { Big * p; p = new (std::nothrow) Big[50000];//8GB if (p == 0) { std::cout << "Could not allocate memory!\n"; exit(EXIT_FAILURE); } std::cout << "Memory successfully allocated!\n"; p[0].stuff[0] = 4; std::cout << p[0].stuff[0] << std::endl; delete [] p; return 0; }
核心是p = new (std::nothrow) Big[50000];//8GB
但是我跑出来的结果,还是抛出异常了,而且由于没有catch块捕捉,所以程序只好调用了terminate函数,然后终止了函数。
大概是我的编译器不支持这个???
terminate called after throwing an instance of 'std::bad_array_new_length'
what(): std::bad_array_new_length
Process returned 3 (0x3) execution time : 0.708 s
Press any key to continue.
像上面所说的,标准C++库把异常和继承结合的方式是:从exception类派生出两个,再从这两个类中继续派生。
除了这种方式,还有别的方法把异常和继承联系在一起: 在类定义中嵌套异常类声明,以组合异常。 把这种嵌套类作为基类,派生出新的类。
天哪,,,我都不知道自己在敲什么了,头皮发麻,眼睛发干发涩,脖子僵硬酸痛,听着音乐振奋精神。。。写了快一个小时
在Sales类的公有部分定义了一个嵌套类用作异常类,继承了logic_error类,
//sales.h -- exceptions and inheritance #ifndef _SALES_H_ #define _SALES_H_ #include <stdexcept> #include <string> class Sales { public: enum {MONTHS = 12}; //嵌套类 ,在公有部分嵌套,派生类和外界可访问 class bad_index : public std::logic_error { private: int bi; public: explicit bad_index(int ix, const std::string & s = "Index error in Sales Object\n"); int bi_val() const {return bi;} virtual ~bad_index()throw(){}//虚析构函数 }; explicit Sales(int yy = 0); Sales(int yy, const double * gr, int n); virtual ~Sales(){} int Year() const {return year;} virtual double operator[](int i)const; virtual double & operator[](int i); private: double gross[MONTHS]; int year;//变量不可和方法名相同 }; class LabeledSales : public Sales { public: class nbad_index : public Sales::bad_index { private: std::string lbl; public: nbad_index(const std::string & lb, int ix, const std::string & s = "Index error in LabledSales object\n"); const std::string & label_val() const {return lbl;} virtual ~nbad_index()throw(){} }; explicit LabeledSales(const std::string & lb = "none", int yy = 0); LabeledSales(const std::string & lb, int yy, const double * gr, int n); virtual ~LabeledSales(){} const std::string & Label() const {return label;} virtual double operator[](int i) const; virtual double & operator[](int i); private: std::string label; }; #endif
//sales.cpp -- methods for class Sales #include <iostream> #include "sales.h" using std::string; Sales::bad_index::bad_index(int ix, const string & s) : std::logic_error(s), bi(ix) {} Sales::Sales(int yy) { year = yy; int i; for (i=0;i<MONTHS;++i)//初始化为0 gross[i] = 0; } Sales::Sales(int yy, const double * gr, int n) { year = yy; int lim = (n < MONTHS) ? n : MONTHS; int i; for (i=0;i<lim;++i) gross[i] = gr[i]; for (;i<MONTHS;++i)//剩下几个月的初始化为0 gross[i] = 0; } double Sales::operator[](int i) const { if (i < 0 || i > MONTHS - 1) throw bad_index(i); return gross[i]; } double & Sales::operator[](int i) { if (i < 0 || i > MONTHS - 1) throw bad_index(i); return gross[i]; } LabeledSales::nbad_index::nbad_index(const string & lb, int ix, const string & s):Sales::bad_index(ix, s) { lbl = lb; } LabeledSales::LabeledSales(const string & lb, int yy):Sales(yy) { label = lb; } LabeledSales::LabeledSales(const string & lb, int yy, const double * gr, int n):Sales(yy, gr, n) { label = lb; } double LabeledSales::operator[](int i) const { if (i < 0 || i >= MONTHS) throw nbad_index(Label(), i); return Sales::operator[](i); } double & LabeledSales::operator[](int i) { if (i < 0 || i >= MONTHS) throw nbad_index(Label(), i); return Sales::operator[](i); }
//use_sales.cpp -- nested exceptions嵌套异常 #include <iostream> #include "sales.h" int main() { using std::cout; using std::cin; using std::endl; double vals1[12] = { 1220, 1100, 1122, 2212, 1232, 2334, 2884, 2393, 3302, 2922, 3002, 3544 }; double vals2[12] = { 12, 11, 22, 21, 32, 34, 28, 29, 33, 29, 32, 35 }; Sales sales1(2011, vals1, 12); LabeledSales sales2("Blogstar", 2012, vals2, 12); cout << "First try block:\n"; try{ int i; cout << "Year = " << sales1.Year() << endl; for (i=0;i<12;++i) { cout << sales1[i] << ' '; if (i % 6 == 5) cout << endl; } cout << "Year = " << sales2.Year() << endl; cout << "Label = " << sales2.Label() << endl; for (i=0;i<=12;++i) { cout << sales2[i] << ' '; if (i % 6 == 5) cout << endl; } cout << "End of try block 1.\n"; } catch (LabeledSales::nbad_index & bad){ cout << bad.what(); cout << "Company: " << bad.label_val() << endl; cout << "bad_index: " << bad.bi_val() << endl; } catch (Sales::bad_index & bad){ cout << bad.what(); cout << "bad_index: " << bad.bi_val() << endl; } cout << "\nNext try block:\n"; try { sales2[2] = 37.5; sales1[20] = 23345; cout << "End of try block 2.\n"; } catch (LabeledSales::nbad_index & bad){ cout << bad.what(); cout << "Company: " << bad.label_val() << endl; cout << "bad index: " << bad.bi_val() << endl; } catch (Sales::bad_index &bad){ cout << bad.what(); cout << "bad index: " << bad.bi_val() << endl; } cout << "done\n"; return 0; }
First try block: Year = 2011 1220 1100 1122 2212 1232 2334 2884 2393 3302 2922 3002 3544 Year = 2012 Label = Blogstar 12 11 22 21 32 34 28 29 33 29 32 35 Index error in LabledSales object Company: Blogstar bad_index: 12 Next try block: Index error in Sales Object bad index: 20 done
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。