zoukankan      html  css  js  c++  java
  • C++异常处理assert,throw,exit用法

    常见的几个小细节问题。

    • assert应用:

          在现实世界中,我们脑袋时刻都在判断对与错,对的事情我们会继续深入下去,而错的事情我们会马上停止,那么在编程开发中我们如何赋予程序这种判断事物对错的能力呢?其中一个方案就可以使用断言assert,我们最常用的地方就是在函数中检查形参的数据合法性。

    1、函数所属头文件:

            assert.h

    2、函数原型:

            void assert (int expression);

    3、功能说明:

            assert的关键在于判断expression的逻辑真假,如果为false,就会在stderr上面打印一条包含“表达式,文件名,行号”的错误信息,然后调用abort结束整个程序。

    4、程序实例:

    #include <stdio.h>
    #include <stdlib.h>
    //#define NDEBUG        //可以禁止断言
    #include <assert.h>
    
    void main()
    {
        //测试true情况:以写打开一个文件,不存在则创建新文件
        FILE *fpWrite = fopen("d:\testWrite", "w");
    
        //不会出错
        assert(fpWrite != NULL);
    
        fclose(fpWrite);
    
        //测试false情况:以读打开一个文件,不存在会失败
        FILE *fpRead = fopen("d:\testRead", "r");
    
        //会出错
        assert(fpRead != NULL);
    
        //程序调用abort退出,不会执行到此步
        fclose(fpRead);
        system("pause");
    }

    结果:

        当然,频繁的调用assert会影响系统性能,增加系统额外的开销,如果想禁用断言功能时,可以在assert.h头文件之前定义NDEBUG。

    • throw应用:

    出错是时可以用throw,然后在catch里面处理,
    asert只是一个debug的检查,检查条件的真假,在release下asert语句不会被调用。

        抛出异常(也称为抛弃异常)即检测是否产生异常,在C++中,其采用throw语句来实现,如果检测到产生异常,则抛出异常。该语句的格式为:
    throw 表达式;
        如果在try语句块的程序段中(包括在其中调用的函数)发现了异常,且抛弃了该异常,则这个异常就可以被try语句块后的某个catch语句所捕获并处理,捕获和处理的条件是被抛弃的异常的类型与catch语句的异常类型相匹配。由于C++使用数据类型来区分不同的异常,因此在判断异常时,throw语句中的表达式的值就没有实际意义,而表达式的类型就特别重要。

        eg:除数为0的异常可以用try/catch语句来捕获异常,并使用throw语句来抛出异常,从而实现异常处理,实现代码:

    #include <iostream>
    using namespace std;
    double fuc(double x, double y)
    {
        if (y == 0)
        {
            throw y;
        }
        return x / y;
    }
    void main()
    {
        double res;
        try
        {
            res = fuc(2, 3);
            cout << "the result of x/y is" << res << endl;
            res = fuc(4, 0);
        }
        catch (double)
        {
            cerr << "error of dividing zero.
    ";
            exit(1);
        }    
    }

    1、基础介绍

    try
    {
        //程序中抛出异常
        throw value;
    }
    catch (valuetype v)
    {
        //例外处理程序段
    }

    语法小结:throw抛出值,catch接受,当然,throw必须在“try语句块”中才有效。

    2、深入throw:
    (i)、程序接受到throw语句后就会自动调用析构器,把该域(try后的括号内)对象clean up,然后再进
    入catch语句(如果在循环体中就退出循环)。

    这种机制会引起一些致命的错误,比如,当“类”有指针成员变量时(又是指针!),在 “类的构建器
    ”中的throw语句引起的退出,会导致这个指针所指向的对象没有被析构。这里很基础,就不深入了,提
    示一下,把指针改为类就行了,比如模板类来代替指针,在模板类的内部设置一个析构函数。

    (ii)、语句“throw;”抛出一个无法被捕获的异常,即使是catch(...)也不能捕捉到,这时进入终止函数
    ,见下catch。

    3、深入catch:
    一般的catch出现的形式是:
    try{}
    catch(except1&){}
    catch(except2&){}
    catch(...){} //接受所有异常
    一般都写成引用(except1&),原因很简单,效率。

    问题a:抛出异常,但是catch不到异常怎么办?(注意没有java类似的finally语句
    在catch没有捕获到匹配的异常的时候,会调用默认的终止函数。可以调用set_terminate()来设置终止函数,参数是一个函数指针,类型是:void (*terminate)()。

    到这里,可以题个问题:“没有try-catch,直接在程序中"throw;",会怎么样?”

    其他一些技巧:
    4、try一个函数体,形式如下

    void fun(type1,type2) try----try放在函数体后
    {
       函数定义
    }
    catch(typeX){}
    这个用法的效果就相当于:
    void fun() 
    {
       try{函数定义}
    }

    5、throw一个函数体,形式如下:

    void fun (); // 能抛出任何类型的异常
    void fun () throw(except1,except2,except3) 
                   // 后面括号里面是一个异常参数表,本例中只能抛出这3中异常
    void fun () throw()   // 参数表为空,不能抛出异常

    问题b:假设fun()中抛出了一个不在“异常参数表”中的异常,会怎么样?

    答:调用set_terminate()中设定的终止函数。然而,这只是表面现象,实际上是调用默认的unexpected()函数,然而这个默认的unexpected()调用了set_terminate()中设定的终止函数。可以用set_unexpected()来设置 unexpected,就像set_terminate()一样的用法,但是在设定了新的“unexpected()”之后,就不会再调用 set_terminater中设定的终止函数了。

    这个语法是很有用的,因为在用别人的代码时,不知道哪个地方会调用什么函数又会抛出什么异常,用一个异常参数表在申明时限制一下,很实用。

    • exit()应用:

    函数: exit()

    函数名: exit()
    所在头文件:stdlib.h(如果是”VC6.0“的话头文件为:windows.h)
    功 能: 关闭所有文件,终止正在执行的进程。
    exit(1)表示异常退出.这个1是返回给操作系统的。
    exit(x)(x不为0)都表示异常退出;
    exit(0)表示正常退出。
    exit()的参数会被传递给一些操作系统,包括UNIX,Linux,和MS DOS,以供其他程序使用。
    stdlib.h: void exit(int status);
    参 数 : status //程序退出的返回值
     
    exit()和return的区别:
    按照ANSI C,在最初调用的main()中使用return和exit()的效果相同。
    但要注意这里所说的是“最初调用”。如果main()在一个递归程序中,exit()仍然会终止程序;但return将
    控制权移交给递归的前一级,直到最初的那一级,此时return才会终止程序。return和exit()的另一个区别
    在于,即使在除main()之外的函数中调用exit(),它也将终止程序。
    _exit()与exit的区别:
    头文件:
    exit:#include<stdlib.h>
    _exit:#include<unistd.h>
    _exit()函数:直接使进程停止运行,清除其使用的内存空间,并销毁其在内核中的各种数据结构;
    exit()函数则在这些基础上作了一些包装,在执行退出之前加了若干道工序。
    exit()函数与_exit()函数最大的区别就在于 exit()函数在调用 exit 系统调用之前要检查文件的打开情况,把文件缓冲区中的内容写回文件。
  • 相关阅读:
    jetty运行服务
    对象的属性值是数组,如何使用ko跨页面绑定?
    Maven打包时出现“Show Console View”错误弹出框,错误详情为“An internal error has occurred. java.lang.NullPointerException”的解决方法
    记录一次CDH集群邮件报警功能的设置
    jupyter notebook
    MacOS开发环境搭建
    Manico--自定义应用快速切换
    Synergy--跨平台的键鼠共享工具
    Sublime Text3 个人使用安装设置
    Typora--我用过的最好用的markdown编辑器
  • 原文地址:https://www.cnblogs.com/ranjiewen/p/5549929.html
Copyright © 2011-2022 走看看