C + + Exceptions ~ a turn

Source: Internet
Author: User
Tags modifier

Read Catalogue

    • Overview of C + + exception mechanisms
    • throw keyword
    • Exception Object
    • catch keyword
    • Stack expansion, RAII
    • Exception mechanism and constructor function
    • Anomaly mechanism and destructor
    • Noexcept modifier and noexcept operator
    • Performance analysis of exception handling

Body

Back to top overview of C + + exception mechanisms

Exception handling is a language mechanism for C + + that handles exception events in a program. Exception events are represented as exception objects in C + +. When an exception event occurs, the program throws an exception expression with the Throw keyword, throws a point called the exception occurrence point, sets the current exception object for the program by the operating system, and then executes the program's current exception-handling code block, at the most inner try block that contains the point at which the exception occurred. Match the exception object in the Catch statement in turn (only type matching, which is sometimes not used in catch statements). If the match succeeds, execute the exception-handling statement inside the catch block, then execute the try...catch ... Code after the block. If in the current Try...catch ... A catch statement that matches the exception object cannot be found within the block, then the outer try...catch ... Block to handle the exception, if all the try...catch in the current function ... Block does not match the exception, recursion passes back to the previous layer of the call stack to handle the exception. Call the system function terminate () to terminate the program if the exception is not handled until the main function main () is returned.
One of the simplest try...catch ... The example below is shown below. We have a program to remember the class students exam results, test scores in the range of 0-100, not in this range as data anomalies:

Int main () {int score =0; while (cin >> score) { try {if (Score > 100 | | Score < 0) {throw score;} //write fractions to file or do other things} catch (int score) {cerr <<  "you entered the score value has a problem, please re-enter!" "; continue;}}           
Go back to the top of the Throw keyword

In the above example,throw is a keyword, and the throw expression forms a throw statement. Its syntax is:

throw 表达式;

The throw statement must be contained in a try block or in a try block that is included in the outer function of the call stack, such as:

Example code: Throw contained in a try block of an outer functionvoid Registerscore(IntScore) {if (Score >100 | | Score <0)Throw score;//throw statement is included in the outer main try statement block // Write fractions to files or perform other operations}int  main () {int score=0; while (cin >> score) { try {Registerscore (score);} catch (int score) {cerr <<  "you entered the score value has a problem, please re-enter!" "; continue;}}           

When a throw statement is executed, the throw expression is constructed as a new object, called the exception object, as an object. The exception object is placed in a special location in memory, which is neither a stack nor a heap, and is placed in the thread information block TIB on the window. This constructed new object is type-matched to the catch statement corresponding to this level of try, and the principle of type matching is described below.

In this example, the object type constructed by score is an int, and a catch (int score) match, the program control is transferred to the catch's statement block, and the exception handling code is executed. If the type of the catch statement does not match successfully within this function, the outer function of the call stack continues to match, so the recursive execution is executed until the catch statement is matched, or the system function terminate () terminates the program until the main function does not match.
When a throw statement is executed, the statement following the throw statement is no longer executed, and the syntax of the throw statement is somewhat similar to return, so that the function on the call stack may exit early.

Go back to the top of the exception object

The exception Object is a special object that the compiler constructs exception objects based on an exception-throwing expression, which requires that an exception expression be thrown not to be an incomplete type (a type is defined before the declaration as an incomplete type. An incomplete type means that the type does not have a complete description of the data and operations, and it is possible to make a copy construct, which requires a copy constructor (or move constructor) of an exception-throwing expression, and the destructor cannot be private.

The exception object is different from the local object of the function, and the local object is automatically destroyed after the function call ends, and the exception object resides in the memory space that can be accessed by all the catch statements that may be activated, which is the TIB mentioned above. When the exception object matches the catch statement successfully, it is automatically refactored at the end of the catch statement.

A reference or pointer that returns a local variable in a function will almost certainly cause an error, and similarly, a pointer or reference that throws a local variable in a throw statement is almost the wrong behavior. If the variable pointed to by the pointer has been destroyed while executing the catch statement, the dereference of the pointer has unintended consequences.

When you throw an expression, the static compilation type of the expression determines the type of the exception object. So when a throw out is a dereference of a base-class pointer, and the actual object that the pointer points to is a derived class object, a derived class object cut occurs.

In addition to throwing user-defined types, the C + + standard library defines a set of classes that users report about problems encountered by standard library functions. These standard library exception classes define only a few operations, including creating or copying exception type objects, and assigning values to objects of the exception type.

Standard Exception class Description header File
exception The most common exception class that only reports the occurrence of an exception without providing any additional information exception
Runtime_error Errors can only be detected at run time Stdexcept
Rang_error Run-time error: Results are generated that exceed the range of meaningful ranges Stdexcept
Overflow_error Run-time error: Calculation overflow Stdexcept
Underflow_error Run-time error: Calculating underflow Stdexcept
Logic_error Program Logic Error Stdexcept
Domain_error Logic error: The result value corresponding to the parameter does not exist Stdexcept
Invalid_argument Logic error: Invalid parameter Stdexcept
Length_error Logic error: An attempt was made to create an object that exceeds the maximum length of the type Stdexcept
Out_of_range Logic error: Using a value beyond the valid range Stdexcept
Bad_alloc Memory Dynamic allocation error New
Bad_cast dynamic_cast Type Conversion Error Type_info
Go back to top catch keyword

The catch statement matches the exception object that was thrown. If the parameter of a catch statement is a reference type, the parameter can be applied directly to the exception object, that is, the change of the parameter will also alter the exception object, and the change will continue to be passed when the exception is re-thrown in the catch. If the catch parameter is a value, the copy constructor constructs a catch parameter object based on the exception object. At the end of the catch statement, the catch Parameter object is first destructor, and then the exception object is refactored.

The compiler does not do any implicit type conversions or type promotion when a match is made to the exception object. The type of the exception object must exactly match the declaration type of the catch statement, except for the following cases:

    • Allows type conversions from very to constant.
    • Allows a type conversion of a derived class to a base class.
    • The array is converted to a pointer to an array (element) type exponentially.
    • The function is converted to a pointer to the function type.

In the process of finding a catch statement, the match is not necessarily the type that exactly matches that item, but the catch statement on the first match (which I call the first matching principle). Therefore, the processing code catch statement for the derived class should precede the processing of the catch statement for the base class, or the first match will always be a catch statement with the parameter type base class, and the catch statement that can match exactly cannot be matched.

In a catch block, if the exception cannot be resolved within the current function, you can continue to throw an exception to the outer layer and let the outer catch exception handling block proceed. You can use a throw statement without an expression to re-throw the caught exception:

catch(type x){    //做了一部分处理    throw;}

The thrown exception object is the exception object that is saved in the TIB, not related to the parameter object of the catch, and if the catch parameter object is a reference type, the exception object may have been modified within the catch statement, then the modified exception object is re-thrown If the catch parameter object is a non-reference type, the re-thrown exception object is not modified.

Use catch (...) {} can catch all types of exceptions, according to the first matching principle, catch (...) {} should be placed on the last side of all catch statements, otherwise it will not be possible to match other catch statements that can match exactly. Usually in catch (...) The {} statement performs the currently available processing and then re-throws the exception. Note that the exception that is re-thrown in a catch can only be caught by the outer catch statement.

Back to top stack unfold, RAII

In fact, the stack expansion has been said in the previous, that is, from the exception throw point all the way to the outer function to find the matching catch statement process, to find the end of a matching catch statement or standard library function terminate. The emphasis here is on the destruction of local variables during stack unwinding. We know that at the end of a function call, the local variables of the function are automatically destroyed by the system, and similarly, throw may cause the statement block on the call chain to exit prematurely, at which point the local variables in the statement block are called in reverse order of the constituent generation, and then the destructor is invoked to destroy the object. For example, the following example:

A class that doesn't make any senseClass a{Public:a (): A (0) {cout <<"A default constructor" <<Endl AConst a& RSH) {cout <<  "a copy constructor" << ENDL; } ~a () {cout <<  "A destructor" << ENDL; }private: int A;}; int main () {try {a A; throw A;} catch (a A) {;} return 0;}         

The program will output:

The default constructor was called when the variable A was defined, the copy constructor was called when the exception variable was initialized with a, and the copy constructor was also called when the catch parameter object was copied using the exception variable. Three constructs correspond to three destructors, that is, the local variable A in the TRY statement block is automatically refactored. However, if a is the memory allocated on the free storage area:

int main(){ try { A * a= new A; throw *a; } catch (A a) { ; } getchar(); return 0;}

Program Run Result:

The same three-time constructs, but only two times the destructor is called! Note that the memory of A is not released when an exception occurs and a memory leak occurs.
the RAII mechanism helps to solve this problem , RAII (Resource acquisition is initialization, resource acquisition is initialization). Its idea is to manage resources with objects . To make it easier and more robust to release the acquired resources and avoid resource deadlocks, one way is to encapsulate the resource data with objects. When an exception occurs and the execution stack expands, the object that encapsulates the resource is automatically called its destructor to free up resources. Smart pointers in C + + conform to RAII. More on this issue can be seen in the "effective C + +" clause.

Back to top exception mechanism and constructors

A reasonable use of the exception mechanism is in the constructor. The constructor does not return a value, so an exception mechanism should be used to report the problem. More importantly, the constructor throws an exception to indicate that the constructor has not finished executing, its corresponding destructor is not automatically called, so the destructor should first destructor all the initialized base object, member object, and then throw an exception.
The exception mechanism for C + + class constructor initialization lists is called Function-try block. The general form is:

myClass::myClass(type1 pa1)    try:  _myClass_val (初始化值) {   /*构造函数的函数体 */}   catch ( exception& err ) { /* 构造函数的异常处理部分 */};
Back to top exception mechanism and destructor

C + + does not prohibit destructors from throwing exceptions to outsiders, but destructors are expected not to throw exceptions to outside functions. The destructor throws an exception outside the function, and the Terminator () system function is called directly to terminate the program. If an exception is thrown inside a destructor, the exception should be caught inside the destructor and handled, and the exception cannot be thrown out of the destructor. This can be handled as follows:

    • If a destructor throws an exception, call Std::abort () to terminate the program.
    • Catch catches exceptions in destructors and is processed.

For details, it is interesting to see the effective C + + clause: don't let the exception escape the destructor .

Back to top noexcept modifier and noexcept operator

The Noexcept modifier is a new exception specifier provided by C++11, which declares that a function does not throw an exception. The compiler is able to optimize for functions that do not throw exceptions, and another obvious benefit is that you know that a function does not throw an exception, and that when someone calls your function, they do not need to do an exception capture for that function. You might see this code in the C++98 program for exception handling:

void func  () throw ( intdouble) { ...} void func () throw () {...}           

This is a throw as a function exception description, which indicates that the Func () function may throw an int or double type exception, which indicates that the Func () function does not throw an exception. In fact the former is rarely used, and in c++11 this practice has been abandoned, while the latter is replaced by the C++11 noexcept Anomaly declaration:

void func() noexcept {...}//等价于void func() throw(){...}

In c++11, the compiler does not check the Noexcept declaration of a function at compile time, so a function declared as noexcept can be compiled by carrying an exception-throwing statement. If an exception is thrown when the function is run, the compiler can choose to call the Terminate () function directly to terminate the program's operation, so one of the functions of noexcept is to prevent the propagation of the exception and improve security .

As mentioned above, we cannot let the exception escape from the destructor, because that will lead to ambiguous behavior of the program or terminate the program directly. In fact, for security reasons, the C++11 standard allows the class's destructor to be noexcept by default. Also for security reasons, often the destructor is used to release the delete function of the resource, and c++11 is set to Noexcept by default.

Noexcept can also accept a constant expression as a parameter, for example:

void func() noexcept(常量表达式);

The result of a constant expression is converted to type bool, noexcept (BOOL) means that the function does not throw an exception, and Noexcept (false) indicates that the function may throw an exception. So if you want to change the default noexcept declaration for destructors, you can explicitly add noexcept (false) declarations, but that doesn't give you any benefit.

Back to top exception handling performance analysis

The main link of the exception handling mechanism is the run-time type check. When an exception is thrown, you must determine whether the exception is thrown from the try block. Exception handling mechanism in order to perfect the match between the exception and its processor, we need to store the type information of each exception object and the additional information of the catch statement. Because an exception object can be of any type, such as a user-defined type, and can also be polymorphic, getting its dynamic type must use run-time type checking (RTTI), and also requires runtime code information and the structure of each function.

When the function of the exception throw point is unable to resolve the exception, the exception object is passed along the call chain, and the control of the program is transferred. During the transfer process, in order to carry the information of the exception object to the execution of the program (such as the copy construction of the exception object or the destruction of the catch parameter), it has to pay a certain price in time and space, and it is inherently unsafe, especially when the exception object is a complex class.

Exception handling techniques are implemented differently under different platforms and compilers, but add additional burdens to the program, and when exception handling is turned off, additional data structures, lookup tables, and some additional code are not generated, because of this, for functions that explicitly do not throw exceptions, We need to use noexcept to declare.

C + + Exceptions ~ a turn

Related Article

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.