1.返回错误码与abort函数
#include <iostream>
using namespace std;
int factorial(int n) // 计算阶乘
{
if(n < 0)
{
cout << "n不能小于0" << endl;
abort();
// return -1; // 返回错误码
}
if(n == 0)
{
return 1;
}
else
{
return n * factorial(n - 1);
}
}
int main(int argc, const char * argv[]) {
// 返回错误码和abort函数
// 返回错误码和abort的不足:
// 1. 当异常条件非常多时,可能无法枚举所有的异常条件,或者遗忘部分的异常条件
// 2. 对函数或方法返回的错误码没有进行判断,可能会造成严重的后果
int n = -10;
int result = factorial(n);
if(result > 0) // 对函数或方法返回的错误码进行判断
{
cout << "n! = " << result << endl;
}
else if(result == -1) // 对函数或方法返回的错误码进行判断
{
cout << "n不能小于0" << endl;
}
return 0;
}
2.引发异常与捕捉异常(throw,try...catch)
#include <iostream>
using namespace std;
int factorial(int n)
{
if(n < 0)
{
throw string("n不能小于0"); // 作用类似goto,会跳到catch里进行处理,
//同时将throw后面的值作为参数传给catch
}
if(n == 0)
{
return 1;
}
else
{
return n * factorial(n - 1);
}
}
void process()
{
try {
int n = -10;
int jc = factorial(n);
cout << n << "! = " << jc << endl;
}
//catch (const char* s)
catch(string s)
{
cout << s << endl;
}
}
int main(int argc, const char * argv[]) {
// 引发异常与捕捉异常(throw、try...catch)
// 1. 引发异常 throw
// 2. 将可能产生异常的代码用try...catch括起来
// 3. 在catch中处理异常
// 优点:不需要对factorial的返回值进行判断,如果有异常发生,直接通过throw跳到异常处理的程序段
process();
return 0;
}
3.将对象作为异常表达式抛出
#include <iostream>
using namespace std;
class ExceptionClass1
{
public:
int code;
string msg;
};
class ExceptionClass2
{
public:
float value;
string msg;
};
void exceptionFunction()
{
int n = 0;
if(n < 0)
{
ExceptionClass1 ec1;
ec1.code = n;
ec1.msg = "n不能小于0";
throw ec1;
}
else if(n == 0)
{
ExceptionClass2 ec2;
ec2.value = 100.5;
ec2.msg = "n不能等于0";
throw ec2;
}
else
{
cout << "n = " << n << endl;
}
}
int main(int argc, const char * argv[]) {
// 将对象作为异常表达式抛出
try
{
exceptionFunction();
}
catch(ExceptionClass1 &ec1)
{
cout << "ec1.code = " << ec1.code << endl;
cout << ec1.msg << endl;
}
catch(ExceptionClass2 &ec2)
{
cout << "ec2.value = " << ec2.value << endl; // 100.5
cout << ec2.msg << endl; // n不能等于0
}
return 0;
}
4.异常捕捉的else
#include <iostream>
using namespace std;
class ExceptionClass
{
public:
float value;
string msg;
string exceptionClass;
};
class ExceptionClass1 : public ExceptionClass {
public:
int code;
};
class ExceptionClass2 : public ExceptionClass
{
};
class ExceptionClass3 : public ExceptionClass
{
};
void exceptionFunction()
{
int n = 0;
if(n < 0)
{
ExceptionClass1 ec1;
ec1.code = n;
ec1.msg = "n不能小于0";
ec1.exceptionClass = "ExceptionClass1";
throw ec1;
}
else if(n == 0)
{
ExceptionClass2 ec2;
ec2.value = 100.5;
ec2.msg = "n不能等于0";
ec2.exceptionClass = "ExceptionClass2";
throw ec2;
}
else
{
ExceptionClass3 ec3;
ec3.value = 200.76;
ec3.msg = "n不能大于0";
ec3.exceptionClass = "ExceptionClass3";
throw ec3;
}
}
int main(int argc, const char * argv[]) {
// 异常捕捉的else
try
{
exceptionFunction();
}
/*
这里对每个异常都使用catch捕捉一次,当部分异常的处理方式是一样的时候
这样处理就显得很浪费时间/臃肿
catch(ExceptionClass1 &ec1)
{
cout << "ec1.code = " << ec1.code << endl;
cout << ec1.msg << endl;
}*/
/*catch(ExceptionClass2 &ec2)
{
cout << "ec2.value = " << ec2.value << endl;
cout << ec2.msg << endl;
}
catch(ExceptionClass3 &ec3) //
{
cout << "ec3.value = " << ec3.value << endl;
cout << ec3.msg << endl;
}*/
catch(ExceptionClass &ec)
{
if("ExceptionClass1" == ec.exceptionClass) // 通过使用if语句对异常进行判断执行相应的操作
{
ExceptionClass1 &ec1 = static_cast<ExceptionClass1&>(ec);
cout << "ec1.code = " << ec1.code << endl;
cout << ec1.msg << endl;
}
else // 这里ExceptionClass2和ExceptionClass3的异常处理方式相同,所以用else代替,简洁了代码
{
cout << ec.exceptionClass << endl;
cout << "ec.value = " << ec.value << endl;
cout << ec.msg << endl;
}
}
return 0;
}
5.异常类的基类:exception
#include <iostream>
using namespace std;
// std命名空间为用户设计好了一个异常类的基类:exception
class ExceptionClass1 : public exception // private,protected都不可以
{
};
class ExceptionClass2 : public exception
{
};
int main(int argc, const char * argv[]) {
// 异常类的基类:exception
try
{
throw ExceptionClass2();
}
catch(ExceptionClass1 &ec1) // 子类ExceptionClass1的引用
{
cout << "ExceptionClass1" << endl;
}
catch(exception &e) // 基类exception的引用
{
cout << "exception" << endl; // 打印 exception
}
return 0;
}
6.throw和noexcept
用throw关键字限制抛出异常的对象的类型,在C++11中不建议使用
#include <iostream>
using namespace std;
clss ExceptionClassA
{
};
clss ExceptionClassB
{
};
void process1() throw(ExceptionClassA,ExceptionClassB) // 在这里使用throw关键字,来限定抛出
// 的内容的类型应该是ExceptionClassA和ExceptionClassB这种的,即不允许抛出字符串形式的异常
{
throw "出错了"; // 此处在运行时会报错,
}
int main( int argc, const char *argv[] ){
try
{
process1();
}
catch(const char *s)
{
cout << s << endl;
}
return 0;
}
#include <iostream>
using namespace std;
clss ExceptionClassA
{
};
clss ExceptionClassB
{
};
void process1() throw(ExceptionClassA,ExceptionClassB)
{
throw ExceptionClassA();
}
int main( int argc, const char *argv[] ){
try
{
process1();
}
catch(const char *s)
{
cout << s << endl;
}
catch(ExceptionClassA *a)
{
cout << "ExceptionClassA" << endl;
}
return 0;
}
C++11中的 noexcept
#include <iostream>
using namespace std;
clss ExceptionClassA
{
};
clss ExceptionClassB
{
};
void process1() throw(ExceptionClassA,ExceptionClassB)
{
throw ExceptionClassA();
}
void process2() noexcept // 表示函数process2()里面不能抛出任何异常
{
throw "hello world";
}
void process3() noexcept(false) // 负负得正,允许抛出异常
{
throw "hello world";
}
int main( int argc, const char *argv[] ){
try
{
process1();
}
catch(const char *s)
{
cout << s << endl;
}
catch(ExceptionClassA *a)
{
cout << "ExceptionClassA" << endl;
}
return 0;
}
#include <iostream>
using namespace std;
clss ExceptionClassA
{
};
clss ExceptionClassB
{
};
void process1() throw(ExceptionClassA,ExceptionClassB)
{
throw ExceptionClassA();
}
template <class T>
void process2() noexcept(sizeof(T) < 4) // T为char short时,不允许抛出异常,T为int、long
// 时,允许抛出异常
{
throw "hello world";
}
template <class T>
void process3(int n) noexcept(sizeof(T) < 4 && n < 100)
{
throw "hello world";
}
int main( int argc, const char *argv[] ){
try
{
process3<int>(100); // 允许抛出异常
}
catch(const char *s)
{
cout << s << endl;
}
catch(ExceptionClassA *a)
{
cout << "ExceptionClassA" << endl;
}
return 0;
}
7.系统的预定义异常类
// 会按照套路/模板写即可,目前还没理解
#include <iostream>
#include <stdexcept>
using namespace std;
class MyException : public exception // exception的子类
{
private:
const char *mWhat;
public:
explicit MyException(const char *s)
{
mWhat = s;
}
virtual const char* what() const _NOEXCEPT
{
return mWhat;
}
};
int main(int argc, const char * argv[]) {
// 系统预定义的异常类
// exception
// logic_error
// runtime_error
int n = 30;
try
{
if(n == 10)
{
throw length_error("长度错误"); // 隶属于logic_error
}
else if(n == 20)
{
throw out_of_range("超出范围"); // 隶属于logic_error
}
else if(n == 30)
{
throw MyException("MyException异常");
}
}
catch(length_error &length)
{
cout << length.what() << endl;
}
catch(logic_error &logic)
{
cout << logic.what() << endl;
}
catch(exception &e)
{
cout << e.what() << endl; // MyException异常
}
return 0;
}
8.捕获由new产生的异常
#include <iostream>
#include <new>
using namespace std;
struct Big
{
double array[3000000000000];
};
int main(int argc, const char * argv[]) {
// 由new产生的异常,new分配空间过大,会产生bad_alloc错误
Big *big;
try
{
big = new Big[10000]; // 这里是分配10000个array[3000000000000]大小的空间,如果不用try...catch,一定会抛出异常
}
catch (bad_alloc &ba)
{
cout << "下面是错误信息" << endl;
cout << ba.what() << endl; // 使用what方法返回错误信息
exit(EXIT_FAILURE); // 相当于 return 1;
}
delete [] big; // 如果电脑太好,有可能分配成功,这句话用来防止分配成功
return 0;
}
9.阻止new抛出异常
#include <iostream>
#include <new>
using namespace std;
struct Big
{
double array[3000000000000];
};
int main(int argc, const char * argv[]) {
// 阻止new抛出异常
Big *big;
try
{ // 在new后面加nothrow后,如果内存分配失败,不会抛出异常,而是会返回空指针给big
big = new(nothrow) Big[10000]; // nullptr
if(big == nullptr)
{
cout << "分配内存空间失败." << endl;
exit(EXIT_FAILURE);
}
}
catch (bad_alloc &ba) // 此处不会执行
{
cout << "下面是错误信息" << endl;
cout << ba.what() << endl;
exit(EXIT_FAILURE); // return 1;
}
delete [] big;
return 0;
}