zoukankan      html  css  js  c++  java
  • C++一些注意点之异常处理

          几篇文章:(1)http://blog.csdn.net/daheiantian/article/details/6530318

                                             (2)http://blog.chinaunix.net/uid-21411227-id-1826957.html

          程序中的错误分为编译时的错误和运行时的错误。编译时的错误主要是语法错误,编译器能够检查出来。而运行时的错误则不容易修改,因为其中的错误是不可预料的,或者可以预料但无法避免的,比如内存空间不够,或者在调用函数时,出现数组越界等错误。如果对于这些错误没有采取有效的防范措施,那么往往会得不到正确的运行结果,程序不正常终止或严重的会出现死机现象。我们把程序运行时的错误统称为异常,对异常处理称为异常处理。C++中所提供的异常处理机制结构清晰,在一定程度上可以保证程序的健壮性。


    C语言异常处理方法

          在C语言的世界中,对错误的处理总是围绕着两种方法:一是使用整型的返回值标识错误;二是使用errno宏(可以简单的理解为一个全局整型变量)去记录错误。当然C++中仍然是可以用这两种方法的。

           缺陷:(1)出现不一致问题。例如有些函数返回1表示成功,返回0表示出错;而有些函数返回0表示成功,返回非0表示出错。

                     (2)函数的返回值只有一个,你通过函数的返回值表示错误代码,那么函数就不能返回其他的值。当然,你也可以通过指针或者C++的引用来返回另外的值,但是这样可能会令你的程序略微晦涩难懂。

           使用异常的好处:函数的返回值可以忽略,但异常不可忽略。如果程序出现异常,但是没有被捕获,程序就会终止,这多少会促使程序员开发出来的程序更健壮一点。而如果使用C语言的error宏或者函数返回值,调用者都有可能忘记检查,从而没有对错误进行处理,结果造成程序莫名其面的终止或出现错误的结果。


    C++异常处理

      C++的异常处理机制有3部分组成:try(检查),throw(抛出),catch(捕获)。把需要检查的语句放在try模块中,检查语句发生错误,throw抛出异常,发出错误信息,由catch来捕获异常信息,并加以处理。

    语法结构如下:

     

    try 
    { 
          //可能引发异常的代码 
    } 
    catch(type_1 e) 
    { 
          // type_1类型异常处理 
    } 
    catch(type_2 e) 
    { 
         // type_2类型异常处理 
    } 
    catch (...)//会捕获所有未被捕获的异常,必须最后出现 
    { 
    } 

    注意:

          (1)try和catch块中必须要用花括号括起来,即使花括号内只有一个语句也不能省略花括号;

          (2)try和catch必须成对出现,一个try_catch结果中只能有一个try块,但可以有多个catch块,以便与不同的异常信息匹配;

          (3)如果在catch块中没有指定异常信息的类型,而用删节号"...",则表示它可以捕获任何类型的异常信息;

          (4)如果throw不包括任何表达式,表示它把当前正在处理的异常信息再次抛出,传给其上一层的catch来处理;

          (5)C++中一旦抛出一个异常,如果程序没有任何的捕获,那么系统将会自动调用一个系统函数terminate,由它调用abort终止程序;

    范例1:

     

    #include <iostream>
    
    template <typename T>
    T Div(T x,T y)
    {
    	if(y==0)
    		throw y;//抛出异常
    	return x/y;
    }
    
    int main()
    {
    	int x=5,y=0;
    	double x1=5.5,y1=0.0;
    	try
    	{
    		//被检查的语句
    		std::cout<<x<<"/"<<y<<"="<<Div(x,y)<<std::endl;
    		std::cout<<x1<<"/"<<y1<<"="<<Div(x1,y1)<<std::endl;
    	}
    	catch(int)//异常类型
    	{
    		std::cout<<"除数为0,计算错误!"<<std::endl;//异常处理语句
    	}
    	catch(double)//异常类型
    	{
    		std::cout<<"除数为0.0,计算错误!"<<std::endl;//异常处理语句
    	}
    	system("pause");
    	return 0;
    }


    执行过程:因为在执行的时候抛出了异常,执行catch(int)里面的语句,然后执行return 0,执行结束,所以double
    Div(x1/y1)根本没有执行。

    C++标准库提供的一些异常类:


     标准异常类的成员: 
            ① 在上述继承体系中,每个类都有提供了构造函数、复制构造函数、和赋值操作符重载。 
            ② logic_error类及其子类、runtime_error类及其子类,它们的构造函数是接受一个string类型的形式参数,用于异常信息的描述; 
            ③ 所有的异常类都有一个what()方法,返回const char* 类型(C风格字符串)的值,描述异常信息。

       标准异常类的具体描述 

    异常名称

    描述

    exception 所有标准异常类的父类
    bad_alloc 当operator new and operator new[],请求分配内存失败时
    bad_exception 这是个特殊的异常,如果函数的异常抛出列表里声明了bad_exception异常,当函数内部抛出了异常抛出列表中没有的异常,这是调用的unexpected函数中若抛出异常,不论什么类型,都会被替换为bad_exception类型
    bad_typeid 使用typeid操作符,操作一个NULL指针,而该指针是带有虚函数的类,这时抛出bad_typeid异常
    bad_cast 使用dynamic_cast转换引用失败的时候
    ios_base::failure io操作过程出现错误
    logic_error 逻辑错误,可以在运行前检测的错误
    runtime_error 运行时错误,仅在运行时才可以检测的错误

            logic_error的子类: 

     

    异常名称

    描述

    length_error 试图生成一个超出该类型最大长度的对象时,例如vector的resize操作
    domain_error 参数的值域错误,主要用在数学函数中。例如使用一个负值调用只能操作非负数的函数
    out_of_range 超出有效范围
    invalid_argument 参数不合适。在标准库中,当利用string对象构造bitset时,而string中的字符不是’0’或’1’的时候,抛出该异常

     

            runtime_error的子类: 

     

    异常名称

    描述

    range_error 计算结果超出了有意义的值域范围
    overflow_error 算术计算上溢
    underflow_error 算术计算下溢


    编写自己的异常类

     1. 为什么要编写自己的异常类? 
          ① 标准库中的异常是有限的; 
          ② 在自己的异常类中,可以添加自己的信息。(标准库中的异常类值允许设置一个用来描述异常的字符串)。

    2. 如何编写自己的异常类? 

          ① 建议自己的异常类要继承标准异常类。因为C++中可以抛出任何类型的异常,所以我们的异常类可以不继承自标准异常,但是这样可能会导致程序混乱,尤其是当我们多人协同开发时。 

          ② 当继承标准异常类时,应该重载父类的what函数虚析构函数。 
          ③ 因为栈展开的过程中,要复制异常类型,那么要根据你在类中添加的成员考虑是否提供自己的复制构造函数



     

    c++异常处理注意的几个问题

     C++中处理异常的过程:在执行程序发生异常,可以不在本函数中处理,而是抛出一个错误信息,把它传递给上一级的函数来解决,上一级解决不了,再传给其上一级,由其上一级处理。如此逐级上传,直到最高一级还无法处理的话,运行系统会自动调用系统函数terminate,由它调用abort终止程序。

     

         以下注意问题:

       (1)性能问题。这个一般不会成为瓶颈,但是如果你编写的是高性能或者实时性要求比较强的软件,就需要考虑了。

       (2)指针和动态分配导致的内存回收问题:在C++中,不会自动回收动态分配的内存,如果遇到异常就需要考虑是否正确的回收了内存。

       (3)C++中是如果你没有在函数的异常抛出列表指定要抛出的异常,意味着你可以抛出任何异常。

       (4)C++中编译时不会检查函数的异常抛出列表。这意味着你在编写C++程序时,如果在函数中抛出了没有在异常抛出列表中声明的异常,编译时是不会报错的。

       (5)C++中,你可以抛出任何类型,你甚至可以抛出一个整型。(当然,在C++中如果你catch中接收时使用的是对象,而不是引用的话,那么你抛出的对象必须要是能够复制的。这是语言的要求,不是异常处理的要求)。


  • 相关阅读:
    linux安装python3.6以后报错处理
    cent07设置服务开机自启
    python进程和线程中的两个锁
    针对Material主题怎么修改 phpstorm 代码编辑器的样式
    CentOS中zip工具的基本使用
    Anaconda退出Base环境
    微擎用户自动回复对应的链接、控制器、模板
    微擎应用模块中的参数设置对应的前端页面
    微擎设置借用权限
    微擎分配不同的用户具有不同应用的操作权限
  • 原文地址:https://www.cnblogs.com/riskyer/p/3260300.html
Copyright © 2011-2022 走看看