C++ exception handling mechanism examples and detailed explanation

  • 2020-04-02 02:13:07
  • OfStack

These two days I wrote an example of testing c++ exception handling mechanism, I feel it has a good demonstration effect, posted here, for c++ exception handling beginners. This article with c++ abnormal knowledge popularization, interested people can also see.

The following code is posted directly to your console project, where you can run debugging to see the results and analyze the c++ exception mechanism.


#include "stdafx.h" 
#include<stdlib.h> 
#include<crtdbg.h> 
#include <iostream> 
//& have spent Memory leak detection mechanism
#define _CRTDBG_MAP_ALLOC 
#ifdef _DEBUG 
#define new new(_NORMAL_BLOCK, __FILE__, __LINE__) 
#endif 
//& have spent Custom exception classes
class MyExcepction 
{ 
public: 
//& have spent Constructor with an error code argument
MyExcepction(int errorId) 
{ 
//& have spent Output constructor called information
std::cout << "MyExcepction is called" << std::endl; 
m_errorId = errorId; 
} 
//& have spent Copy constructor
MyExcepction( MyExcepction& myExp) 
{ 
//& have spent Output copy constructor called information
std::cout << "copy construct is called" << std::endl; 
this->m_errorId = myExp.m_errorId; 
} 
~MyExcepction() 
{ 
//& have spent Output destructor called information
std::cout << "~MyExcepction is called" << std::endl; 
} 
//& have spent Get error code
int getErrorId() 
{ 
return m_errorId; 
} 
private: 
//& have spent Error code
int m_errorId; 
}; 
int main(int argc, char* argv[]) 
{ 
//& have spent Memory leak detection mechanism
_CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF ); 
//& have spent You can change the error code to throw different exceptions for testing
int throwErrorCode = 110; 
std::cout << " input test code :" << std::endl; 
std::cin >> throwErrorCode; 
try 
{ 
if ( throwErrorCode == 110) 
{ 
MyExcepction myStru(110); 
//& have spent The address & NBSP; of the thrown object; -> & have spent By the catch (& have spent MyExcepction * & have spent PMyExcepction) & have spent capture
//& have spent Here the object's address is thrown to the catch statement and the copy constructor of the object is not called
//& have spent Address passing is encouraged and the constructor or copy constructor of the object is not called frequently
//& have spent After the catch statement is executed,myStru is destructed
throw &myStru; 
} 
else if ( throwErrorCode == 119 ) 
{ 
MyExcepction myStru(119); 
//& have spent Throws an object, which is passed out to catch by creating a temporary object through the copy constructor
//& have spent By the catch (& have spent MyExcepction  MyExcepction) & have spent capture
//& have spent In the catch statement it is called again to create a temporary object by the copy constructor to copy the object that was passed over here
//& have spent When throw is done, myStru will be destroyed
throw myStru; 
} 
else if ( throwErrorCode == 120 ) 
{ 
//& have spent Such a throw method is not recommended
//& have spent If you do this, if you catch(& NBSP; MyExcepction * & have spent Memory leaks occur if the delete operation is not performed in pMyExcepction)
//& have spent By the catch (& have spent MyExcepction * & have spent PMyExcepction) & have spent capture
MyExcepction * pMyStru = new MyExcepction(120); 
throw pMyStru; 
} 
else 
{ 
//& have spent Directly create a new object to throw
//& have spent The equivalent of creating a temporary object and passing it to the catch statement
//& have spent The temporary object is created again by the copy constructor when received by catch to receive the passed object
//& have spent Temporary objects created twice after throw are destroyed
throw MyExcepction(throwErrorCode); 
} 
} 
catch( MyExcepction* pMyExcepction) 
{ 
//& have spent Output information about the statement being executed
std::cout << " To perform the  catch( MyExcepction* pMyExcepction) " << std::endl; 
//& have spent Output error message
std::cout << "error Code : " << pMyExcepction->getErrorId()<< std::endl; 
//& have spent The new object thrown by the exception is not created on the function stack, but on a dedicated exception stack, without the need for delete
//delete pMyExcepction; 
} 
catch ( MyExcepction myExcepction) 
{ 
//& have spent Output information about the statement being executed
std::cout << " To perform the  catch ( MyExcepction myExcepction) " << std::endl; 
//& have spent Output error message
std::cout << "error Code : " << myExcepction.getErrorId()<< std::endl; 
} 
catch(...) 
{ 
//& have spent Output information about the statement being executed
std::cout << " To perform the  catch(...) " << std::endl; 
//& have spent Can't handle it, rethrow it to the superior
throw ; 
} 
//& have spent suspended
int temp; 
std::cin >> temp; 
return 0; 
} 

C++ exception mechanism

An overview,

C++ itself has a very strong error correction ability, development to the present, has established a relatively perfect exception handling mechanism. C++ exceptions occur in one of two ways. One is a syntax error, in which the program has incorrect statements, functions, structures, and classes that prevent the program from being compiled. The other is an error that occurs at run time, usually related to an algorithm.

Needless to say, syntax errors can be fixed by writing code with a bit of care. The C++ compiler's error reporting mechanism allows us to easily resolve these errors.

The second is a run-time error, common to open a file failure, an array index overflow, the system out of memory, and so on. Once these problems occur, it is common to cause failure of algorithm and stop the program without reason. This requires us to design software algorithms to be comprehensive. For example, in case of file opening failure, there are many ways to protect, the simplest is to use the "return" command, tell the upper layer of the caller function execution failure; Another strategy is to use c++ 's exception mechanism to throw exceptions.

C++ exception handling mechanism

The C++ exception handling mechanism is a very powerful and flexible tool for effectively handling run errors, providing more flexibility, security, and robustness than the traditional approach.

Exceptions are thrown and handled using the following three keywords: try, throw, catch.

Throwing an exception is to detect whether an exception is generated. In C++, it is implemented by the throw statement. If an exception is detected, an exception is thrown. The format of this statement is:
Throw expression;
If an exception is found in the program segment of a try block (including the function called in it) and it is discarded, the exception can be caught and processed by a catch statement after the try block, provided that the type of the exception being thrown matches the type of the catch statement. Because C++ USES data types to distinguish different exceptions, the value of the expression in the throw statement has no real meaning when determining exceptions, and the type of the expression is particularly important.

The try-catch statement is as follows:


try 
{ 
 Contains statements that might throw exceptions;  
} 
catch( Type name  [ Parameter name ]) //& have spent Catch specific types of exceptions
{ 
} 
catch( Type name  [ Parameter name ]) //& have spent Catch specific types of exceptions
{ 
} 
catch(...) //& have spent The three points represent catching all types of exceptions
{ 
} 

Example 1 handles exceptions with a divisor of 0. This example allows exceptions whose divisor is 0 to be caught by a try/catch statement and thrown by a throw statement, as shown in listing 1-1.
// listing 1-1

#include<iostream.h> //Include header file
#include<stdlib.h> 
double fuc(double x, double y) //Define a function
{ 
if(y==0) 
{ 
throw y; //Divisor 0, throws an exception
} 
return x/y; //Otherwise returns the quotient of two Numbers
} 
void main() 
{ 
double res; 
try //Define abnormal
{ 
res=fuc(2,3); 
cout<<"The result of x/y is : "<<res<<endl; 
res=fuc(4,0);  An exception is thrown inside the function  
} 
catch(double) //Catch and handle exceptions
{ 
cerr<<"error of dividing zero.n"; 
exit(1); //Exception exit program
} 
} 

[example 2] custom exception types (demonstrated in the code at the beginning of this article)

Three, the exception of the interface declaration

In order to enhance the readability of the program, so that the user of the function can easily know which exceptions will be thrown by the function used, the declaration of the function can list all types of exceptions that the function may throw, such as:

void   Fun ()   Throw (A, B, C, D);

This means that the function fun() can and only can throw exceptions of types (A,B,C,D) and their subtypes.

If an interface declaration for an exception is not included in the declaration of the function, the function can throw an exception of any type, such as: void   Fun ();

A function that does not throw any type of exception can be declared as follows:

void   Thow fun () ();

Five, the exception processing needs to pay attention to the problem

1. If the exception is thrown without a catch, it will be uploaded to the c++ runtime, causing the entire program to terminate

2. Generally, the resource can be normally released after the exception is thrown, but notice that if the exception is thrown in the constructor of the class, the system will not call its destructor. The handling method is: if the exception is thrown in the constructor, remember to delete the requested resource before throwing it.

3. Exception handling is matched only by type, not by value, so the parameter of catch block can have no parameter name, just the parameter type.

4. The exception description in the function prototype should be consistent with the exception description in the implementation, otherwise it is easy to cause exception conflicts.

5. When the exception object should be written after the throw statement, throw first constructs a new object through the Copy constructor and then passes the new object to catch.  

So how is the new object released when an exception is thrown?
The exception handling mechanism guarantees that the new object thrown by the exception is not created on the function stack, but on a dedicated exception stack, so that it can be passed across multiple functions to the upper level, or it will be destroyed during stack empting. Destructors for all objects constructed between the try and throw statements are automatically called. But if a matching catch block is not found all the way up to the main function, the system calls terminate() to terminate the entire program, in which case there is no guarantee that all local objects will be properly destroyed.

6. The parameter of catch block is recommended to be passed by address instead of value, which can not only improve the efficiency, but also take advantage of the polymorphism of the object. In addition, the exception catch of derived classes is placed in front of the parent exception catch; otherwise, the exception of derived classes cannot be caught.

7. When writing the exception description, make sure that the exception description of the derived class member function is consistent with the exception description of the base class member function, that is, the exception description of the virtual function overridden by the derived class should be at least the same as the exception description of the corresponding base class virtual function, or even more strict and special.


Related articles: