c++的异常处理demo

来源:互联网 发布:欧朋浏览器java黑莓版 编辑:程序博客网 时间:2024/04/28 02:45

//下面的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();
}