异常概念
- 异常处理就是处理程序中的错误
- 种类很多,包括返回异常等等
异常优势
- 函数返回值可以忽略,但异常不可忽略,没有被捕获就会程序终止
- 整形返回值没有任何语义信息,而异常包含语义信息,有时类名即可体现
- 整形返回值缺乏上下文信息,异常作为一个类,可以拥有自己的成员,成员可以传递足够的信息
- 异常处理可以在调用跳级,这是一个代码编写问题;假设在有多个函数调用栈中出现了某个错误,使用整型返回码要求你在每一个级函数中都要进行处理,而使用异常处理的栈展开机制,只需要在一处进行处理就可以了,不需要每一级函数都处理
异常基本语法
- 异常捕获不是相互依赖的,可以跨函数
- 异常时必须处理,否则程序会宕掉
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
//异常基本语法
int divide(int x, int y)
{
if (y == 0)
{
throw y;//抛异常
}
return x / y;
}
void test01()
{
//尝试捕获异常
try
{
divide(10, 0);
}
catch (int e)
{
//异常时根据类型进行匹配
cout << "除数为" << e << "!" << endl;
}
}
void CallDivide(int x,int y)
{
divide(x,y);
}
void test02()
{
try {
CallDivide(10, 0);
}
catch (int e)
{
cout << "test02除数为" << e << "!" << endl;
}
}
int main(void)
{
test01();
test02();
return 0;
}
栈解旋
- 抛出异常,函数中的局部变量会被析构,就跟return一样
异常接口声明
-
为了加强程序的可读性,可以在函数声明中列出所有可能抛出异常的所有类型
例如void func()throw(A,B,C)
这个函数func能够只抛出类型A,B,C及其子类型的异常
-
如果函数声明中没有包含异常接口声明,则此函数可以抛出任何类型的异常,例如:void func()
-
一个不抛任何类型异常的函数可声明为:void func()throw()
-
如果一个函数抛出它的异常接口声明所不允许抛出的异常,unexcepted函数会被调用,该函数默认行为调用terminate函数中断程序
-
代码示例
#define _CRT_SECURE_NO_WARNINGS #include<iostream> using namespace std; void func() throw(int,float,char) { throw "abc"; } //不能抛出异常 void func2()throw() {}; int main(void) { try { func(); } catch (const char* str) { cout << str << endl; } catch (int e) { cout << "异常" << e << endl; } catch (...)//捕获所有异常 { cout << "捕获所有异常!" << endl; } return 0; }
异常类型和异常变量的生命期
-
throw的异常是有类型的,可以是数字、字符串、类对象
-
throw的异常是有类型的,catch需要严格匹配异常类型
-
注意异常对象的内存模型
-
异常捕获对象时可以使用对象的方法属性等
-
捕获的是对象时要有对象的拷贝构造并且重载等号运算符
-
代码示例
#define _CRT_SECURE_NO_WARNINGS #include<iostream> using namespace std; void func01() { throw 1; } void func02() { throw "exception"; } class MyException { public: MyException(const char* str) { error = new char[strlen(str) + 1]; strcpy(error, str); } MyException(const MyException& ex) { this->error = new char[strlen(ex.error) + 1]; strcpy(this->error, ex.error); } MyException& operator=(const MyException& ex) { if (this->error != NULL) { delete[] this->error; this->error = NULL; } this->error = new char[strlen(ex.error) + 1]; strcpy(this->error, ex.error); } void what() { cout << this->error << endl; } ~MyException() { if (this->error != NULL) { cout << "~Myexception()..." << endl; delete[] this->error; } } public: char* error; }; void func03() { throw MyException("我刚写的异常"); } void test01() { try { func01(); } catch (int e) { cout << "test01捕获异常" << e << endl; } try { func02(); } catch (const char* str) { cout << "func02捕获异常" << str << endl; } try { func03(); } catch (MyException e) { cout << "catch()..." << endl; e.what(); } } int main(void) { test01(); return 0; }
异常对象生命周期
-
普通元素异常catch处理完只有就析构
-
catch如果用引用去接不会有拷贝构造,异常处理完析构
-
catch指针时,要先new对象,否则没有内存指针无法赋值
-
代码示例
#define _CRT_SECURE_NO_WARNINGS #include<iostream> using namespace std; class MyException { public: MyException() { cout << "构造函数!" << endl; } MyException(const MyException& ex) { cout << "拷贝构造!" << endl; } ~MyException() { cout << "析构函数!" << endl; } }; void func() { //throw MyException();//创建匿名对象,调用构造函数 throw new MyException();//catch用指针时,要new,否则会提前被析构 } void test01() { //可以有普通类型元素 引用 指针三种 try { func(); } /*catch (MyException e) { cout << "普通元素异常捕获!" << endl; }*/ /*catch (MyException &e) { cout << "引用异常捕获!" << endl; }*/ catch (MyException* e) { cout << "指针异常捕获!" << endl; delete e; } } int main(void) { test01(); return 0; }
C++标准异常类
-
一般是自己的异常类去继承标准exception类,标准库有限,可以添加自己信息
-
如何编写自己的异常类
- 继承标准异常类,否则容易导致程序混乱,开发难以协调
- 继承标准类时,应该重载父类的what函数和虚析构函数
- 栈展开过程中,要复制异常类型,要根据在类中添加的成员考虑是否提供自己的复制构造函数
-
-
-
代码示例
#define _CRT_SECURE_NO_WARNINGS #include<iostream> #include<stdexcept> using namespace std; class Person { public: Person() { this->mAge = 0; } void setAge(int age) { if (age < 0 || age>100) { throw out_of_range("年龄应该在0-100之间"); } this->mAge = age; } public: int mAge; }; void test01() { Person p; try { p.setAge(1000); } catch (exception e) { cout << e.what() << endl; } } class MyOutRange:public exception { public: MyOutRange(const char* error) { this->pError = new char[strlen(error) + 1]; strcpy(this->pError, error); } ~MyOutRange() { if (this->pError != NULL) { delete[] this->pError; } } virtual char const* what() const { return pError; }; public: char* pError; }; void func02() { throw MyOutRange("我自己的的out_of_range!"); } void test02() { try { func02(); } catch (exception &e)//抛出异常类型不同 { cout << e.what() << endl; } } int main(void) { test01(); test02(); system("pause"); return 0; }
继承在异常中的应用
代码示例
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<stdexcept>
#include<string>
using namespace std;
//异常基类
class BaseMyException
{
public:
virtual void what() = 0;
virtual ~BaseMyException()
{
};
};
class TargetSpaceNullExpection :public BaseMyException
{
public:
virtual void what()
{
cout << "子类目标空间为空!" << endl;
}
};
class SourceSpaceNullExpection :public BaseMyException
{
public:
virtual void what()
{
cout << "源空间为空!" << endl;
}
~SourceSpaceNullExpection() {};
};
void copy_str(char* taget, char* source)
{
if (taget == NULL)
{
throw TargetSpaceNullExpection();
//cout << "目标空间为空" << endl;
return;
}
if (source == NULL)
{
throw SourceSpaceNullExpection();
//cout << "源空间为空" << endl;
}
int len = strlen(source) + 1;
while (*source!='\0')
{
*taget = *source;
taget++;
source++;
}
}
int main(void)
{
char* source = new char[]("abcefg");
//char* source = "abcdef";
char buf[1024] = {0};
try
{
copy_str(buf,NULL);
}
catch (BaseMyException& ex)
{
ex.what();
}
cout << buf << endl;
return 0;
}