c++_note_9_异常处理

版权声明:本文为博主原创文章,转前请跟博主吱一声。 https://blog.csdn.net/Ga4ra/article/details/89818408

10. 异常

基本语法有两种:

  • 抛出异常
  • 捕获处理。

发生异常后:

  • throw抛出,若被捕捉,则跨函数直接跳到匹配的catch()保护段;
  • 若无法处理,可以再次throw向上抛出;
  • 若没有处理,则引发中断。

throw会创建一个异常对象并抛出。

构造函数没有返回值,经常配合异常机制使用。

捕捉是严格按照类型匹配的,匹配程度近乎模板匹配,不允许任何类型转换。

#include<iostream>
using namespace std;

void divide(int a, int b)
{
	if (b == 0)
	{
		throw 1;
	}
	cout<<a/b<<endl;
}

int main(int argc, char *argv[])
{
	try
	{
		divide(4,2);
		divide(1,0);	
	}
	
	catch(int e)
	{
		cout<<"divide 0 error."<<endl;
	}
	catch( ... )
	{
		cout<<"Unknown exception."<<endl;
	}
	cin.get();
	return 0;
}
/*
2
divide 0 error.
*/

10.1 异常的基本思想

传统的错误处理是基于函数返回值,以栈结构展开的上下函数衔接的程序控制系统;而异常依附于栈结构,可以在栈中跳跃回馈。

异常的引发和异常的处理不必在同一个函数中,这样底层的函数可以着重解决具体问题,而不必过多的考虑异常的处理。上层调用者可以再适当的位置设计对不同类型异常的处理。

异常处理基本思想

10.2 unwinding

栈解旋:从进入try开始,到异常被抛出前,期间的对象会自动析构。

#include<iostream>
using namespace std;

class MyException:public exception{};

class MyClass
{
public:
	int a;
	MyClass(int a)
	{
		this->a = a;
	}
	~MyClass()
	{
		cout<<"destruct "<<a<<endl;
	}
};

void func() throw(MyException)
{
	throw MyException();
}

int main(int argc, char *argv[])
{
	try
	{
		MyClass c1(1),c2(2);
		func();
	}
	catch(MyException &e)
	{
		cout<<"MyException."<<endl;
	}
	
	cin.get();
	return 0;
}

/*
destruct 2
destruct 1
MyException.
*/

10.3 异常接口声明

为了加强可读性,在函数声明中列出所有可能抛出的异常。

void func() throw(A,B,C),则该函数只能抛出A,B,C及其子类类型的异常。

若没有声明,则可以抛出任何异常。

若抛出没有声明的异常,则会调用包含terminate()unexpected()函数终止程序。

10.4 异常变量的生命周期

刚刚说过,throw创建异常对象,catch严格按照类型匹配。

下面是根据返回值进行错误处理。

int func()
{
    {
        ...
        return 1;
    }
    return 0;
}
int main()
{
    int ret = func();
    if(ret != 0)
    {
        switch(ret)
        {}
    }
    return 0;
}

下面是异常处理。

void func()
{
    throw 1;
}
int main()
{
    try
    {
        func();
    }
    catch(int e)	//若用不到e,可以写为catch(int)
    {}
    return 0;
}

该例抛出的1位于静态常量区。

下面是抛出异常类型。

void func()
{
    throw MyException();	//匿名对象
}
int main()
{
    try
    {
        func();
    }
    catch(MyException e)	//若用不到e,可以写为catch(int)
    {}
    return 0;
}

抛出的匿名异常类型对象,仍然遵循函数调用规则,调用拷贝构造方法复制给e

如果catch(MyException &e),则直接使用抛出时的匿名对象。

指针也可以捕捉:throw new MyException; catch(MyException *e){delete e};当然我们不会这样用.

10.5 继承在异常中的应用

创建一个数组类来演示异常的层次结构如何使用.

#include<iostream>
using namespace std;

class MyArray{
private:
	int *p;
	int len;
public:
	MyArray(int len);
	~MyArray();
	//int & operator[](int index);
	
	class eSize
	{
	public:
		virtual void printStackTrace() = 0;
	};
	
	class eNeg : public eSize 
	{
	public:
		eNeg() : eSize(){}
		virtual void printStackTrace()
		{
			cout<<"len < 0"<<endl;
		}
	};
	class eZero : public eSize 
	{
	public:
		eZero() : eSize(){}
		virtual void printStackTrace()
		{
			cout<<"len == 0"<<endl;
		}
	};

};

MyArray::MyArray(int len)
{
	if(len < 0)
	{
		throw eNeg();
	}
	else if(len == 0)
	{
		throw eZero();
	}
	this->len = len;
	p = new int[len];
}

MyArray::~MyArray()
{
	if(p != NULL)
	{
		delete [] p;
		p = NULL;
		len = 0;
	}
}

int main(int argc, char *argv[])
{
	try
	{
		MyArray a(-1);
	}
	catch(MyArray::eNeg e)
	{
		e.printStackTrace();
	}
	cin.get();
	return 0;
}
/*
len < 0
*/

10.6 标准异常类

标准库抛出的异常都以Exception为基类。

class exception {
public:
  exception () noexcept;
  exception (const exception&) noexcept;
  exception& operator= (const exception&) noexcept;
  virtual ~exception();
  virtual const char* what() const noexcept;
}

what()用于返回错误信息。

// exception::what
#include <iostream>       // std::cout
#include <exception>      // std::exception
using namespace std;
struct ooops : exception {
  const char* what() const noexcept {return "Ooops!\n";}
};

int main () {
  try {
      throw ooops();
  } catch (exception& ex) {
      cout << ex.what();
  }
  return 0;
}
/*
Ooops!
*/

noexcept是c++ 11加入的关键字,在这之前相当于throw(),即不会抛出异常.

涉及头文件:<exception>,<stdexcept>,<typeinfo>,<new>,<ios>

标准异常类的继承关系如下,具体左转官网

E x c e p t i o n { l o g i c _ e r r o r { d o m a i n _ e r r o r i n v a l i d _ a r g u m e n t l e n g t h _ e r r o r o u t _ o f r a n g e f u t u r e _ e r r o r b a d _ a l l o c b a d _ c a s b a d _ e x c e p t i o n b a d _ f u n c t i o n c a l l b a d _ t y p e i d b a d _ w e a k p t r i o s _ b a s e : : f a i l u r e r u n t i m e _ e r r o r { r a n g e _ e r r o r o v e r f l o w _ e r r o r u n d e r f l o w _ e r r o r s y s t e m _ e r r o r Exception \begin{cases} logic\_error \begin{cases} domain\_error\\ invalid\_argument\\ length\_error\\ out\_of_range\\ future\_error \end{cases}\\ bad\_alloc\\ bad\_cas\\ bad\_exception\\ bad\_function_call\\ bad\_typeid\\ bad\_weak_ptr\\ ios\_base::failure\\ runtime\_error \begin{cases} range\_error\\ overflow\_error\\ underflow\_error\\ system\_error \end{cases} \end{cases}

猜你喜欢

转载自blog.csdn.net/Ga4ra/article/details/89818408
今日推荐