C + + exception handling

Source: Internet
Author: User
Tags throw exception

This paper introduces the concept and practice of C + + exception handling through the way of exception processing, and then deeply analyzes the exception handling mechanism of C + +, special handling of exception handling and exception specification.

1.C language Exception handling 1.1, the concept of exceptions
    • Exception: The program may produce an exception during operation (the execution branch is expected when the program runs), such as: run-time in addition to 0 cases, the need to open an external file does not exist, the array access is out of bounds ...
    • Bug:bug is an error in the program, is not expected to run the way, such as: Wild Pointer, heap memory is not released after the end, select sort cannot handle the length of 0 array ...
1.2, C language exception handling (1) The classic method:

If (judging if an exception is generated)

{

Normal code logic

}

Else

{

Exception code Logic

}

#include <iostream>#include <string>using namespace std;double divide(double a, double b, int* valid){    const double delta = 0.000000000000001;  //判断是否非零    double ret = 0;    if( !((-delta < b) && (b < delta)) )    {        ret = a / b;        *valid = 1;    }    else    {        *valid = 0;    }    return ret;}int main(int argc, char *argv[]){       int valid = 0;    double r = divide(1, 0, &valid);    if( valid )    {        cout << "r = " << r << endl;    }    else    {        cout << "Divided by zero..." << endl;    }    return 0;}

The flaw in this approach is that the exception branch is always taken into account when writing code.

(2) setjmp () and longjmp ()

int setjmp (JMP_BUF env)//Save the current context in the JMP_BUF structure
void longjmp (jmp_buf env, int val)//Restores the setjmp () saved context from the jmp_buf struct, and eventually returns from the SETJMP function call point, the return value is Val

#include <iostream>#include <string>#include <csetjmp>using namespace std;/**缺陷:setjmp()和longjmp()的引入必然涉及到全局变量,暴力跳转导致代码可读性降低***/static jmp_buf env;     //定义全局变量double divide(double a, double b){    const double delta = 0.000000000000001;     //一般不要拿浮点数和0直接做比较    double ret = 0;    if( !((-delta < b) && (b < delta)) )    {        ret = a / b;    }    else    {        longjmp(env, 1);    }    return ret;}int main(int argc, char *argv[]){       if( setjmp(env) == 0 )    {        double r = divide(1, 1);        cout << "r = " << r << endl;    }    else    {        cout << "Divided by zero..." << endl;    }    return 0;}

The execution flow of the above program:

    • int setjmp (JMP_BUF env)//Save the current context in the jmp_buf struct
    • void longjmp (jmp_buf env, int val)
    • Restores the setjmp () saved context from the jmp_buf struct, and eventually returns from the SETJMP function call point, with the return value Val
    • The main function starts, if judgment is bound to be established, and then call the Divide function, when the divisor is 0 o'clock, go to else from the JMP_BUF structure to restore the setjmp () saved context, and finally return from the SETJMP function call point, the return value is Val, The If judgment in the main function is not valid at this point, and entering the else consent error message.

defects:The introduction of setjmp () and longjmp () inevitably involves global variables, and violent jumps lead to lower code readability

2. Exception handling in C + + (i) 2.1. C + + contains syntax elements for exception handling try, catch, throw

--try statement handling of normal code logic

--catch Statement Handling Exception cases

--c++ throwing exception information through a throw statement

Exceptions in a try statement are handled by the corresponding Catch statement

The function throws an exception to the function call (inside the try statement) at run time, and the try statement gives the exception to the corresponding Catch statement to handle

#include <iostream>#include <string>using namespace std;/**函数在运行时抛出(throw)一个异常到函数调用的地方(try语句内部),try语句就会将异常交给对应的catch语句去处理**/double divide(double a, double b){    const double delta = 0.000000000000001;    double ret = 0;    if( !((-delta < b) && (b < delta)) )    {        ret = a / b;    }    else    {        throw 0;    }    return ret;}int main(int argc, char *argv[]){        try    {        double r = divide(1, 0);        cout << "r = " << r << endl;    }    catch(...)    {        cout << "Divided by zero..." << endl;    }    return 0;}   
2.2. C + + exception handling analysis

Exceptions thrown by--throw must be handled by catch

The current function is capable of handling exceptions and the program continues to execute

The current function cannot handle the exception, the function stops executing and returns (the unhandled exception propagates up the function call stack until it is processed, or the program stops executing)

A 2.3try statement can throw any type of exception, and a catch statement can define a specific exception type

--different exceptions are handled by different catch statements

--catch (...) For handling all types of exceptions (can only be placed on the last side)

Note: any exception can only be caught (catch) once, and after the exception is thrown, the capture will strictly match the type processed by each catch statement, without any type of conversion

#include <iostream>#include <string>using namespace std;/**异常抛出后,至上而下将严格的匹配每一个catch语句处理的类型,不进行任何类型的转换**/void Demo1(){    try    {           throw ‘c‘;    }    catch(char c)    {        cout << "catch(char c)" << endl;    }    catch(short c)    {        cout << "catch(short c)" << endl;    }    catch(double c)    {        cout << "catch(double c)" << endl;    }    catch(...)    {        cout << "catch(...)" << endl;    }}void Demo2(){    throw string("D.T.Software");}int main(int argc, char *argv[]){        Demo1();    try    {        Demo2();    }    catch(char* s)    {        cout << "catch(char *s)" << endl;    }    catch(const char* cs)    {        cout << "catch(const char *cs)" << endl;    }    catch(string ss)    {        cout << "catch(string ss)" << endl;    }    return 0;}
3. Exception handling in C + + (bottom) 3.1, catch re-interpretation

(1) The exception caught in catch can be re-interpreted and thrown, and catch throws an exception that requires an outer try...catch ... Capture

Why do you want to re-throw an exception?

In actual engineering, we can capture and re-interpret exceptions thrown in third-party libraries (unify exception types, facilitate code problem positioning), and then throw

#include <iostream> #include <string>using namespace std;void Demo () {try {try {        Throw ' C ';            } catch (int i) {cout << "inner:catch (int i)" << Endl;        throw i;        } catch (...)            {cout << "inner:catch (...)" << Endl;        Throw    }} catch (...)    {cout << "outer:catch (...)" << Endl;                        }}/* hypothesis: The current function is a function in a third-party library, so we cannot modify the source code function name: void func (int i) the type of exception thrown: int-1 = = "parameter exception     -2 = = "Run exception-3 = =" Timeout exception */void func (int i) {if (I < 0) {throw-1;    } if (i >) {throw-2;    } if (i = =) {throw-3; } cout << "Run func ..." << Endl;}    void MyFunc (int i)//call a third-party library function, catch and re-interpret the exception, and then throw {try {func (i);      } catch (int i) {switch (i) {case-1:          Throw "Invalid Parameter";            Catch an exception and re-interpret and throw a break;                Case-2: Throw "Runtime Exception";            Break                Case-3: Throw "Timeout Exception";        Break    }}}int Main (int argc, char *argv[]) {Demo ();    try {MyFunc (11);    } catch (const char* CS) {cout << "Exception Info:" << cs << Endl; } return 0;}

Attention:

The type of the exception can be a custom class type, and the match for the class type exception is still the first and the strict match
The assignment compatibility principle is still applicable in exception matching, generally
Catch of the matching subclass exception is placed in the upper
Catch that matches the parent exception is placed in the lower

#include <iostream> #include the type of <string>using namespace Std;class base{};//exception can be a custom class type class Exception:    public base{int m_id;        string m_desc;public:exception (int id, string desc) {m_id = ID;    M_DESC = desc;    } int ID () const {return m_id;    } string Description () const {return m_desc;                        }};/* hypothesis: The function in the current function-type third-party library, therefore, we cannot modify the source code function name: void func (int i) throw exception type: int-1 = = "parameter exception -2 = = "Run exception-3 = =" Timeout exception */void func (int i) {if (I < 0) {Throw-1    ;    } if (i >) {throw-2;    } if (i = =) {throw-3; } cout << "Run func ..." << Endl;}    void MyFunc (int i) {try {func (i); } catch (int i) {switch (i) {case-1: Throw Exception ( -1, "Invalid Parameter                ");            Break Case-2: Throw Exception (-2,"Runtime Exception");            Break                Case-3: Throw Exception ( -3, "Timeout Exception");        Break    }}}int Main (int argc, char *argv[]) {try {MyFunc (11);    }//When defining a catch statement block, it is recommended to use references as parameters (prevent copy construction)//assignment compatibility principle to remain applicable in exception matching, generally catch (const exception& e)//Match subclass exception catch on top        {cout << "Exception Info:" << Endl;        cout << "ID:" << e.id () << Endl;    cout << "Description:" << e.description () << Endl; } catch (const base& e)//catch with the parent exception is placed in the lower {cout << catch (const base& e) << end    L } return 0;}
(3) Engineering proposal:
    • A series of exception classes are defined in the project, and each class represents an exception type that may occur in the project
    • may need to re-interpret different exception classes when code is reused
    • Reference is recommended as a parameter when defining a catch statement block (prevents copy construction)
3.2. Standard library Anomaly class family

(1) The C + + standard library provides a family of practical exception classes, all derived from the exception class, with two main branches

--logic_error (often used to avoid logic errors in the program)

--runtime_error (often used to avoid malignant errors in the program)

Exceptions in the standard library:

4, Function Exception Specification 4.1: How to tell if a function will throw an exception, will throw those exceptions?

The C + + syntax provides the exception that is used to declare a function to be thrown, and the exception is followed by the modifier write function declaration of the function declaration.

May throw any exception

void fun (void);

can only throw int type exception

void fun (void) throw (int);

Cannot throw an exception

void fun (void) throw ();

#include <iostream>using namespace std;void func() throw(int){    cout << "func()";    cout << endl;    throw ‘c‘;}int main(){    try     {        func();    }     catch(int)     {        cout << "catch(int)";        cout << endl;    }     catch(char)     {        cout << "catch(char)";        cout << endl;    }    return 0;}

The meaning of the exception specification:

    • -Prompt function Call this must prepare for exception handling
    • -Prompt the maintainer of the function not to throw other exceptions
    • -Exception specification is part of the function interface.
4.2: What happens if an exception is thrown that is not in the Declaration list?

The exception thrown by the function is not in the specification, and the global function unexpected () is called

The default unexpected () function calls the global terminate () function

You can customize the unexpected () function

--Function type void (*) (void)

--Ability to throw exceptions again

A) The program resumes execution when the exception that is thrown at the time matches the exception specification function of the triggering function

b) Otherwise, call the Terminate () function to end the program

--Call the set_unexpected () function to set the custom exception function, and return the value to the default unexpected function entry address.

#include <iostream>#include <cstdlib>#include <exception>using namespace std;void my_unexpected(){    cout << "void my_unexpected()" << endl;    // exit(1);    throw 1;}void func() throw(int){    cout << "func()";    cout << endl;    throw ‘c‘;}int main(){    set_unexpected(my_unexpected);    try     {        func();    }     catch(int)     {        cout << "catch(int)";        cout << endl;    }     catch(char)     {        cout << "catch(char)";        cout << endl;    }    return 0;}

Note Not all C + + compilers support this standard behavior, where vs is not supported (the thrown exception is handled directly, although it is not in the exception specification).

5. Exception handling Depth parsing 5.1:main function throws exception

What happens when an exception is thrown in the main function? What happens if the exception is not handled?

The experimental results show that the exception is not handled, which causes the program to end abnormally and print the exception statement.

So where does the exception statement print?

If the exception cannot be handled, the terminate () function is called automatically, which is used to end the exception, and the library function abort () function is called in the Terminate () function to terminate the program (the Abort function causes the program to execute an exception and immediately exits).

#include <iostream>using namespace std;class Test {public:    Test()     {        cout << "Test()";         cout << endl;    }    ~Test()     {        cout << "~Test()";         cout << endl;    }};int main(){    static Test t;    throw 1;    return 0;}    C++语法支持自定义terminate()函数的实现:    (1)定义一个无返回值无参数的函数(函数类型为void(*)()类型)        a)不能抛出异常        b)必须以某种方式结束当前程序(abort/exit/…)    (2)调用set_terminate注册自定义的terminate()函数        a)返回值为默认的terminate函数入口地址。#include <iostream>#include <cstdlib>#include <exception>using namespace std;void my_terminate(){    cout << "void my_terminate()" << endl;    exit(1);}class Test {public:    Test()     {        cout << "Test()";         cout << endl;    }    ~Test()     {        cout << "~Test()";         cout << endl;    }};int main(){    set_terminate(my_terminate);    static Test t;    throw 1;    return 0;}
5.2: destructor Throws exception

What happens when you throw an exception in a destructor?

Experimental results show that the terminate () function is called when an exception is thrown in a destructor in a more stable environment such as Linux. There seems to be no problem, but for some embedded systems, it can lead to system instability.

Conclusion:

The Terminate function is the last chance for the entire program to release resources.

Failure to throw an exception in the destructor causes the Terminate function to be called multiple times, causing the resource to be repeatedly freed.

The Terminate () function in the C + + standard library calls the Abort function, ends the program directly, and no longer calls the destructor, preventing the destructor from throwing out an exception.

#include <iostream>#include <cstdlib>#include <exception>using namespace std;void my_terminate(){    cout << "void my_terminate()" << endl;    // exit(1);    abort();    // C++ 标准库中terminate()函数调用的为abort直接结束程序,不会再去调用析构函数,防止析构函数中还有异常扔出}class Test {public:    Test()     {        cout << "Test()";         cout << endl;    }    ~Test()     {        cout << "~Test()";         cout << endl;        throw 2;    // terminate函数是整个程序释放资源的最后机会                    // 析构函数中不能抛出异常,会导致terminate函数被多次调用,造成资源重复释放    }};int main(){    set_terminate(my_terminate);    static Test t;    throw 1;    return 0;}
6. Other wording of Try ... catch

Try...catch is used to separate the normal logic of code and exception handling code, you can directly separate the function implementation into two parts.

#include <iostream>#include <string>using namespace std;int func(int i, int j) throw(int, char){    if( (0 < j) && (j < 10) )    {        return (i + j);    }    else    {        throw ‘0‘;    }}void test(int i) try{    cout << "func(i, i) = " << func(i, i) << endl;}catch(int i){    cout << "Exception: " << i << endl;}catch(...){    cout << "Exception..." << endl;}int main(int argc, char *argv[]){    test(5);    test(10);    return 0;}

Obviously, this code is less readable. But when it comes to some old code it may come across this notation.
This article is hereby acknowledged as a reference to the teacher's course.

C + + exception handling

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.