798-C + + exception handling (try catch)

C + + exception handling (try catch)

The program often encounters some errors, such as divisor 0, age negative, array subscript out of bounds, etc. if these errors can not be found and handled, they may lead to program crash.
The C + + exception handling mechanism allows us to catch and handle these errors, and then we can let the program continue to execute along a path that will not make errors, or we have to end the program, but we can do some necessary work before the end, such as writing the data in memory to the file, closing the open file, releasing the allocated memory, etc.

Program error classification

It can be roughly divided into three types: syntax error, logic error and runtime error:
1. Syntax errors can be found in the compilation and linking stages. Only 100% of the code that conforms to the syntax rules can generate executable programs. Syntax errors are the easiest to find, locate and eliminate. Programmers don't need to worry about them.

2. Logic error means that the code we write has a problem and cannot achieve the final goal. This error can be solved by debugging.

3. Runtime errors refer to errors that occur during the operation of the program, such as divisor 0, memory allocation failure, array out of bounds, file nonexistence, etc. C + + Exception mechanism is introduced to solve runtime errors.

If the runtime error is left unchecked, the system will execute the default operation and terminate the program, which is often called program Crash. C + + provides an Exception mechanism, which allows us to catch runtime errors, give the program a chance to "come back from the dead", or at least tell the user what happened and then terminate the program.

[example 1] a program with runtime error:

#include <iostream>
#include <string>
using namespace std;
int main() 
{
    string str = "http://c.linzeyu.net";
    char ch1 = str[100];//The subscript is out of bounds, and ch1 is the garbage value
    cout << ch1 << endl;
    char ch2 = str.at(100);//The subscript is out of bounds and an exception is thrown
    cout << ch2 << endl;
    return 0;
}

Run the code and the program crashes after the console outputs the value of ch1.

Let's analyze the reasons.
at() is a member function of the string class, which returns one character of the string according to the subscript. Unlike [], at() checks whether the subscript is out of bounds, and throws an exception if it is out of bounds; [] does not check, and will access as usual regardless of the subscript.
The so-called throwing an exception is to report a runtime error, which can be further handled by the programmer according to the error information.
In the above code, the subscript 100 obviously exceeds the length of the string str. Because the code in line 6 does not check that the subscript is out of bounds, although there is a logic error, the program can run normally. The code in line 8 is different. When the at() function detects that the subscript is out of bounds, it will throw an exception. This exception can be handled by the programmer, but we have not handled it in the code, so the system can only perform the default operation, that is, terminate the program execution.

Catch exception

We can catch the above exceptions with the help of C + + exception mechanism to avoid program crash. The syntax for catching exceptions is:

try
{
    //Statements that may throw exceptions
}catch(exceptionType variable)
{
    //Statement handling exception
}

Try and catch are keywords in C + +, followed by statement blocks. You cannot omit {}. Try contains statements that may throw exceptions. Once an exception is thrown, it will be caught by the following catch. As can be seen from the meaning of try, it only "detects" whether there is an exception in the statement block. If there is no exception, it cannot "detect". Catch means "catch", which is used to catch and handle the exceptions detected by try; If the try statement block does not detect an exception (no exception is thrown), the statement in catch will not be executed.

This is like, catch tells try: check whether the program has errors. If there are errors, tell me. I'll deal with them. If not, don't pay attention to me!

The exceptionType variable after the catch keyword indicates the exception type that the current catch can handle and the specific error information.

[example 2] modify the above code and add a statement to catch exceptions:

#include <iostream>
#include <string>
#include <exception>
using namespace std;
int main() 
{
    string str = "http://c.linzeyu.net";

    try 
    {
        char ch1 = str[100];
        cout << ch1 << endl;
    }
    catch (exception e) 
    {
        cout << "[1]out of bound!" << endl;
    }
    try 
    {
        char ch2 = str.at(100);
        cout << ch2 << endl;
    }
    catch (exception& e) 
    {  //The exception class is located in the < exception > header file
        cout << "[2]out of bound!" << endl;
    }
    return 0;
}


It can be seen that the first try does not catch an exception and outputs a meaningless character (garbage value). Because [] does not check that the subscript is out of bounds and does not throw an exception, try cannot detect any errors. In other words, when an exception occurs, the exception must be explicitly thrown before try can detect it; If it is not thrown out, even if there is an exception, try cannot detect it. The so-called throwing an exception is to clearly tell the program what error has occurred.

The second try detects an exception and sends it to catch to execute the statements in catch. It should be noted that once an exception is thrown, it will be immediately detected by try, and the statements after the exception point (the location of the exception) will not be executed. In this example, the position where the exception is thrown is the at() function on line 17. The cout statement behind it will not be executed again, so its output cannot be seen.

To put it bluntly, after an exception is detected, the execution flow of the program will jump from the exception point to the location of the catch, and the statements behind the exception point and in the current try block will not be executed again; Even if the catch statement successfully handles the error, the execution flow of the program will not fall back to the exception point, so these statements will never have a chance to execute. In this case, line 18 is the skipped code.

After executing the code contained in the catch block, the program will continue to execute the code behind the catch block and resume the normal execution flow.

In order to demonstrate that "no exception can be detected without explicitly throwing an exception", you might as well change the code in line 10 to char ch1 = str[100000000];, There may be no exception when accessing the 100th character, but there must be an exception when accessing the 100th character. This exception is a memory access error. Running the changed program, you will find that an exception occurred in line 10 of the code, resulting in the program crash, which indicates that try catch did not catch this exception.

Throw( Throw)--> Detection( Try) --> Capture( Catch)

Where the exception occurred

Exceptions can occur in the current try block, in a function called by the try block, or in another function called by the called function. These exceptions can be detected by try.

1. The following example demonstrates an exception that occurs directly in the try block:

#include <iostream>
#include <string>
#include <exception>
using namespace std;
int main()
{
    try
	{
        throw "Unknown Exception";//Throw exception
        cout<<"This statement will not be executed."<<endl;
    }catch(const char* &e)
	{
        cout<<e<<endl;
    }
    return 0;
}


Throw keyword is used to throw an exception, which will be detected by try and caught by catch. We will explain the usage of throw in depth in the next blog. Here you only need to know that the exception thrown directly in the try block will be detected by try.

2. The following example demonstrates an exception in a function called in try block:

#include <iostream>
#include <string>
#include <exception>
using namespace std;
void func()
{
    throw "Unknown Exception";//Throw exception
    cout<<"[1]This statement will not be executed."<<endl;
}
int main()
{
    try
	{
        func();
        cout<<"[2]This statement will not be executed."<<endl;
    }catch(const char* &e)
	{
        cout<<e<<endl;
    }
    return 0;
}


func() is called in the try block. The exception thrown by func() will be detected by try and caught by catch. It can be seen from the running results that cout in func() and cout in try are not executed.

3, a function is called in the try block, which calls another function. The other function throws an exception:

#include <iostream>
#include <string>
#include <exception>
using namespace std;
void func_inner()
{
    throw "Unknown Exception";//Throw exception
    cout<<"[1]This statement will not be executed."<<endl;
}
void func_outer()
{
    func_inner();
    cout<<"[2]This statement will not be executed."<<endl;
}
int main()
{
    try
	{
        func_outer();
        cout<<"[3]This statement will not be executed."<<endl;
    }catch(const char* &e)
	{ 
        cout<<e<<endl;
    }
    return 0;
}


After an exception occurs, the execution flow of the program will go back and forth along the function call chain until it meets try. In this rollback process, the remaining code in the call chain, which is not executed in all functions, is skipped and there is no chance to execute.

Keywords: C++ Back-end

Added by kulin on Fri, 12 Nov 2021 09:03:40 +0200