c++的异常处理demo

下面的demo代码可以直接拷贝到文件,并且在g++编译器编译后即可执行

#include <stdlib.h> #include <time.h> #include <stdio.h> #include <unistd.h> #include <string> #include <iostream> using namespace std; //定义用于测试的异常类 class MyException { public: MyException (string name="none") : m_name(name) { cout << "构造一个MyException异常对象,名称为:"<<m_name<< endl; } MyException (const MyException& old_e) { m_name = old_e.m_name; cout << "拷贝一个MyException异常对象,名称为:"<<m_name<< endl; } MyException& operator= (const MyException& old_e) { m_name = old_e.m_name; cout << "赋值拷贝一个MyException异常对象,名称为:"<<m_name<< endl; return *this; } virtual ~ MyException () { cout << "销毁一个MyException异常对象,名称为:" <<m_name<< endl; } string GetName() { return m_name; } protected: string m_name; }; void test_fun1() { try { cout << "1" << endl; // 构造一个异常对象,这是局部变量 MyException ex_obj1("ex_obj1"); cout << "2" << endl; /* 这里抛出异常对象,注意这时编译器会复制一份新的异常对象-临时变量 - 此时相当于return一份到异常栈中,因此会调用拷贝 构造函数并且在跳转之前,把从try到throw之间的局部变量均析构掉(除了异常栈中的那份继续保留-直到对应的catch block 结束才析构)*/ throw ex_obj1; cout << "3" << endl;//不会执行到 } /*这种方式会首先从异常栈中拷贝一份到当前的参数e中,因此调用一次拷贝构造函数,处理完毕后,在catch块结束前 分别调用异常栈中的异常对象和e的析构函数,因此执行两次析构函数的调用,类似函数调用的传参,不同的是异常对象的 实参是从异常栈拷贝到形参e的*/ catch(MyException e) { cout << e.GetName() << endl; //异常栈的异常对象会在catch block 之后调用对应的析构函数销毁掉 } catch(...) { cout<<"catch unknow exception"<<endl; } } void test_fun2() { try { cout << "1" << endl; // 构造一个异常对象,这是局部变量 MyException ex_obj1("ex_obj1"); cout << "2" << endl; /*这里抛出异常对象注意这时编译器会复制一份新的异常对象,临时变量 - 此时相当于return一份到异常栈中,因此调用拷贝构造函数 并且在转换之前,把从try到throw直接的局部变量均析构调*/ throw ex_obj1; } /*这种方式是直接使用异常栈中的异常对象的引用,因此少了一次拷贝对象到e的拷贝构造函数和catch block后的析构函数的调用*/ catch(MyException &e) { cout << e.GetName() << endl; } } //这种方式是最推荐的方法,因为只需构造一次并且析构一次,同时不存在内存泄漏 void test_fun3() { try { //这种方式是直接构造一个异常对象放到异常栈,然后跳转,因此没有局部临时变量的创建和析构 throw MyException("ex_obj1"); } //这种方式是直接使用异常栈中的异常对象的引用,因此少了一次拷贝对象到e的拷贝构造函数和catch block后的析构函数的调用 catch(MyException &e) { cout << "&e" << endl; cout << e.GetName() << endl; } catch(MyException *e) { cout << "*e" << endl; cout << e->GetName() << endl; } } void test_fun4() { try { //这种方式是直接构造一个异常对象放到异常栈,然后跳转,因此没有局部临时变量的创建和析构 throw MyException("ex_obj1"); } //这种方式会首先从异常栈中拷贝一份到当前的参数e中,因此调用一次拷贝构造函数,处理完毕后,在catch块结束前 //分别调用异常栈中的异常对象和e的析构函数,因此执行两次析构函数的调用 catch(MyException e) { cout << e.GetName() << endl; } } //下面考虑指针的方式 void test_fun5() { try { /*可以加入static,让局部变量放到静态存储区,此时可以传地址,并且该对象认为是异常对象,因此在catch block之后也会调用对应的析构函数进行销毁*/ MyException ex_obj1("ex_obj1"); //cout << &ex_obj1 << endl; //MyException *e = &ex_obj1; //cout << e->GetName() << endl; /*这种方式是非法的,此时虽然地址已经抛出去,但对应的exception对象会被析构掉,因此在cache的时候拿到地址也意义不大的 相当于函数调用的return局部变量的地址一样的问题*/ throw &ex_obj1; } catch(MyException *e) { //cout << e << endl; cout << e->GetName() << endl; } } void test_fun6() { try { //不提倡这样的抛出方法,这样如果在catch中不执行delete操作,则会发生内存泄漏  MyException *pEx = new MyException("ex_obj1"); throw pEx; } catch(MyException *e) { //cout << e << endl; cout << e->GetName() << endl; if(NULL != e) { delete e; //但无法确认对应的地址是否是new来构建的,有可能是static 的栈分配的,此时虽然是捕捉地址,但无需delete } } } int main(int iArgC, char ** ppArgV) { test_fun1(); test_fun2(); test_fun3(); test_fun4(); test_fun5(); test_fun6(); } 

你可能感兴趣的:(c++的异常处理demo)