异常是指存在于运行时的反常行为,这些行为超出了函数正常功能的范围。
所以在程序的某部分检测到一个它无法处理的问题时,需要用到异常处理。
首先我们先贴代码
#include "stdafx.h"
#include <iostream>
using namespace std;
template <class T>
class Vector {
public:
Vector(int);
~Vector();
Vector(const Vector&);
Vector& operator=(const Vector& rhs);
T& operator[](int);
private:
T* m_elements;
int m_size;
};
template <class T>
Vector<T>::Vector(int size) :m_size(size) {
cout << "this is constructor" << endl;
m_elements = new T[m_size];
}
template <class T>
Vector<T>::~Vector() {
cout << "this is Destrucor" << endl;
delete[] m_elements;
m_elements = NULL;
}
template<class T>
Vector<T>::Vector(const Vector &)
{
cout << "this is copy construcor" << endl;
}
template <class T>
Vector<T>& Vector<T>::operator=(const Vector& rhs) {
cout << "this is = " << endl;
}
template <class T>
T& Vector<T>::operator[](int index) {
if (index>0 && index<m_size) {
return m_elements[index];
}
else {
cout << "index is invalid" << endl;
}
}//这样处理会发生异常,没有返回值
int main()
{
Vector<int> v1(6);
cout << "hello" << endl;
int i = 1;
for (; i < 6; i++) {
v1[i] = i;
}
cout << i << endl;
return 0;
}
异常时不良的处理有:
- 1 返回值是不缺的内存的值
return m_elements[index];
- 2 错误时,返回一个错误值
T& Vector<T>::operator[](int index) {
if (index<0 || index>=m_size) {
T* error_marker = new T("something magic value");
return *error_marker;
}
return m_elements[index];
}
x = v1[2] + v1[4]; //一旦v1[4]越界,则x无法计算
- 3 退出处理
if(index<0||index>=m_size){
exit(666);
}
return m_elements[index];
- 4 自动判断
assert(index>= 0&& intdex <m_size);
return m_elements[index];
所以这时候,我们可以用关键字 throw
抛出一个异常。
template <class T>
T& Vector<T>::operator[](int index) {
if (index<0 || index>=m_size) {
//throw is a keyword
//exception is raised at this point
throw <<something>>;
}
return m_elements[index];
}
可以通过原始类型或者一个类去表达这个error
class VectorIndexError{
public:
VectorIndexError(int v):m_badValue(v){ }
~VectorIndexError(){ }
void diagnostic(){
cerr <<"index "<< m_badValue<<"out of range!";}
private:
int m_badValue;
};
template <class T>
T& Vector<T>::operator[](int index) {
if (index<0 || index>=m_size) {
//throw is a keyword
//exception is raised at this point
throw VectorIndexError(index);
}
return m_elements[index];
}
#include "stdafx.h"
#include <iostream>
using namespace std;
template <class T>
class Vector {
public:
Vector(int);
~Vector();
Vector(const Vector&);
Vector& operator=(const Vector& rhs);
T& operator[](int);
private:
T* m_elements;
int m_size;
};
template <class T>
Vector<T>::Vector(int size) :m_size(size) {
cout << "this is constructor" << endl;
m_elements = new T[m_size];
}
template <class T>
Vector<T>::~Vector() {
cout << "this is Destrucor" << endl;
delete[] m_elements;
m_elements = NULL;
}
template<class T>
Vector<T>::Vector(const Vector &)
{
cout << "this is copy construcor" << endl;
}
template <class T>
Vector<T>& Vector<T>::operator=(const Vector& rhs) {
cout << "this is = " << endl;
}
class VectorIndexError {
public:
VectorIndexError(int v) :m_badValue(v) { }
~VectorIndexError() { }
void diagnostic() {
cerr << "index " << m_badValue << " out of range!" << endl;
}
private:
int m_badValue;
};
template <class T>
T& Vector<T>::operator[](int index) {
if (index<0 || index >= m_size) {
//throw is a keyword
//exception is raised at this point
throw VectorIndexError(index);
}
return m_elements[index];
}
int func() {
Vector<int> v(12);
v[3] = 5;
int i = v[20]; //out of range!
//control never get here
return 5 * i;
}
void outer() {
try {
func();
//func2();
}
catch (VectorIndexError& o) {
o.diagnostic();
//This exception does not propagate
}
cout << "Control is here after exception";
}
int main()
{
Vector<int> v1(6);
cout << "hello" << endl;
int i = 1;
for (; i < 6; i++) {
v1[i] = i;
}
cout << i << endl;
cout << "do exception test" << endl;
outer();
cout << endl;
return 0;
}
所以异常处理包括:
- throw 表达式,异常检测部分使用 throw 表达式来表示遇到了无法处理的异常问题,即 throw 引发了异常。
- try 语句块,异常处理部分使用 try 语句块处理异常。try 语句块以关键字 try 开始,并以一个或多个 catch 子句解释。
下面给出一个
#include "stdafx.h"
#include <iostream>
#include <string>
using namespace std;
template <class T>
class Vector {
public:
Vector(int);
~Vector();
Vector(const Vector&);
Vector& operator=(const Vector& rhs);
T& operator[](int);
private:
T* m_elements;
int m_size;
};
template <class T>
Vector<T>::Vector(int size) :m_size(size) {
cout << "this is constructor" << endl;
m_elements = new T[m_size];
}
template <class T>
Vector<T>::~Vector() {
cout << "this is Destrucor" << endl;
delete[] m_elements;
m_elements = NULL;
}
template<class T>
Vector<T>::Vector(const Vector &)
{
cout << "this is copy construcor" << endl;
}
template <class T>
Vector<T>& Vector<T>::operator=(const Vector& rhs) {
cout << "this is = " << endl;
}
template <class T>
T& Vector<T>::operator[](int index) {
if (index<0 || index >= m_size) {
//throw is a keyword
//exception is raised at this point
throw VectorIndexError(index);
}
return m_elements[index];
}
class VectorIndexError {
public:
VectorIndexError(int v) :m_badValue(v) { }
~VectorIndexError() { }
void diagnostic() {
cerr << "index " << m_badValue << " out of range!" << endl;
}
private:
int m_badValue;
};
int func() {
Vector<int> v(12);
v[3] = 5;
int i = v[20]; //out of range!
//control never get here
return 5 * i;
}
void outer() {
try {
func();
//func2();
}
catch (VectorIndexError& o) {
o.diagnostic();
//This exception does not propagate
}
cout << "Control is here after exception";
}
void outer2() {
string err("exception caught");
try {
func();
//func2();
}
catch (VectorIndexError) {
cout << err << endl;
throw; //propagate the exception
}
}
void outer3() {
try {
outer2();
}
catch(...){
//... means catchs ALL exception no matter what types(int ,double class exception types)
cout << "The exception stops here!" << endl;
}
}
int main()
{
Vector<int> v1(6);
cout << "hello" << endl;
int i = 1;
for (; i < 6; i++) {
v1[i] = i;
}
cout << i << endl;
cout << "do exception test" << endl;
outer();
cout << endl;
cout << "do exception test2" << endl;
//outer2();
//cout << endl;
outer3();
return 0;
}
机制如下图所示:
异常处理的步骤是:
先顺序执行 throw 表达式,在每一个 throw 表达式里面按顺序执行:
- 1 Check for exact match
2.Apply base class conversions
–Reference and pointer types only3.Ellipses(…)match all
其中, throw 表达式可以理解成函数调用,表达式类型就是异常抛出的类型。