Powerful functions of seh II

Source: Internet
Author: User
Tags finally block

Reproduced from-http://blog.programfan.com/article.asp? Id = 9839

The previous article described the Exception Handling Mechanism of Seh, that is, the rules for using the try-try t model. This article continues to discuss another very important mechanism of Seh, that is, "effectively guaranteeing the removal of resources". In fact, this is the most essential part of seh design. For C Programs, it contributes too much.

This mechanism of seh is called termination handling. It is implemented through try-finally statements. Let's start to discuss it later!

Try-finally

For the purpose of try-Finally, let's take a look at what it says in msdn! Abstract:

The try-finally statement is a Microsoft extension to the C and C ++ languages that enables 32-bit target applications to guarantee execution of cleanup code when execution of a block of code is interrupted. cleanup consists of such tasks as deallocating memory, closing files, and releasing file handles. the try-finally statement is especially useful for routines that have several places where a check is made for an error that cocould cause premature return from the routine.

The content of the above paragraph is translated as follows:

The try-finally statement is Microsoft's extension to the C and C ++ languages. It enables 32-bit target programs to effectively clear some resources in time when exceptions occur, the cleanup tasks of these resources can include the release of memory, the closure of files, and the release of file handles. The try-finally statement is especially suitable for this scenario. For example, in a routine (function), there are several places where an error needs to be detected. When an error occurs, the function may return it in advance.

Try-finally syntax rules

When we describe the role of the try-finally mechanism above, we may not be able to fully understand it at the moment, but it does not matter. Here let's take a look at the try-finally syntax rules first! The sample code is as follows:

// Seh-test.c
# Include <windows. h>
# Include <stdio. h>

Void main ()
{
Puts ("hello ");
_ Try
{
Puts ("_ Try block ");
}
// Note: Here it is not _ blocks t, but _ finally replaced
_ Finally
{
Puts ("_ Finally block ");
}

Puts ("world ");
}

The program running result is as follows:
Hello
_ Try Block
_ Finally block
World
Press any key to continue

The syntax of a try-finally statement is similar to that of a try-finally statement. The difference is that __finally does not have an expression after it, because the try-finally statement is not used for exception processing, therefore, it does not need an expression to determine the type of the current Exception error. In addition, like the try-Finally t statement, try-finally can also be nested in multiple layers, and a function can have multiple try-finally statements, whether nested, or parallel. Of course, try-finally multi-layer nesting can also be cross-function. Examples are not listed here. You can test them yourself.
In addition, do you feel a little unexpected about the running results of the above sample program? Because the put ("_ Finally block") Statement in the _ Finally block is also executed. Yes, that's right! This is where the try-finally statement has the most magical power, that is, "No matter under what circumstances, when you leave the current scope, code in the Finally block area will be executed ". Haha! This is really amazing! To verify this rule, the following is a more typical example. The Code is as follows:

# Include <stdio. h>

Void main ()
{
Puts ("hello ");
_ Try
{
Puts ("_ Try block ");

// Note that the following return statement directly causes the function to return
Return;
}
_ Finally
{
Puts ("_ Finally block ");
}

Puts ("world ");
}

The program running result is as follows:
Hello
_ Try Block
_ Finally block
Press any key to continue

The above program running result is a bit interesting. In the _ Try block area, there is a return statement that causes the function to return directly, so the put ("world") statement is not executed, which is easy to understand. However, please note that the code in the __finally block area will also be executed. Does this further verify the above rule! A Yu was deeply touched and thought, "_ finally's features are really like object destructor." What do my friends think?

In addition, you may be particularly concerned about whether the GOTO statement may damage the above rule? In C language, the GOTO statement generally corresponds to a JMP jump command. If so, the GOTO statement can easily break the above rule. Let's look at a specific example!

# Include <stdio. h>

Void main ()
{
Puts ("hello ");
_ Try
{
Puts ("_ Try block ");

// Jump command
Goto return;
}
_ Finally
{
Puts ("_ Finally block ");
}

Return:
Puts ("world ");
}

The program running result is as follows:
Hello
_ Try Block
_ Finally block
World
Press any key to continue

Haha! Even if the GOTO statement in the preceding example skips the _ Finally block, the code in the _ Finally block area is still executed. Of course, you may be very concerned about why? Why are try-finally statements so amazing? I am not going to elaborate on it in detail here. I will analyze it in detail later on the seh implementation. Here, my friends only remember that "whether it is sequential linear execution, return statements, or goto statements, unconditional jump, etc.
When the execution flow is out of the current scope, the code in the Finally block area will be executed"

Exception in try-Finally block

Only the return and goto statements are listed above. But if an exception occurs in the program, will the code in the Finally block area be executed? Is the rule mentioned above still correct? Let's take a look at the example. The Code is as follows:

# Include <stdio. h>

Void test ()
{
Puts ("hello ");
_ Try
{
Int * P;
Puts ("_ Try block ");

// An exception is thrown below
P = 0;
* P = 25;
}
_ Finally
{
// Will it be executed here?
Puts ("_ Finally block ");
}

Puts ("world ");
}

Void main ()
{
_ Try
{
Test ();
}
_ Partition T (1)
{
Puts ("_ blocks t ");
}
}

The program running result is as follows:
Hello
_ Try Block
_ Finally block
_ Blocks t
Press any key to continue

According to the running results of the sample program above, it is consistent with "no matter under what circumstances, when leaving the current scope, code in the Finally block area will be executed to "this rule is consistent.

Function of the _ leave keyword

In fact, there are three situations when the above _ Finally block execution process is summarized. The first type is to sequentially execute the code in the _ Finally block area. This situation is simple and easy to understand; the second is that when the program control flow caused by the GOTO statement or return statement leaves the current _ Try block scope, the system automatically calls the _ Finally block code; the third is that when an exception occurs in the _ Try block, the control flow of the program leaves the current _ Try block scope, in this case, the system automatically calls the _ Finally block. Whether it is 2nd or 3rd cases, there is no doubt that they will cause a lot of system overhead. When the compiler compiles such program code, it will prepare a lot of additional code for both cases. Generally, it is referred to as "localunwinding" and "globalunwinding" in 2nd cases )". This will be analyzed in detail when we discuss seh implementation later.
In 3rd cases, that is, global expansion caused by exceptions, this may be unavoidable for programmers, this is because when you use the exception handling mechanism to improve program reliability and robustness, it will inevitably lead to other performance overhead. Haha! In fact, the world is fair, and there are gains and losses.

However, in 2nd cases, programmers can effectively avoid it and avoid unnecessary overhead caused by "Local expansion. This is also consistent with the structured program design philosophy, that is, a program module should have only one entry and one exit, and the GOTO statement should be avoided in the program module as much as possible. However, even so, sometimes to improve the readability of the program, the programmer may have to adopt some practices that are contrary to the structured program design idea when writing code. For example, in a function, there may be multiple return statements. In this case, seh provides a very effective compromise, that is, the role of the _ leave keyword, it has the same effect as a GOTO statement and a return statement (because an error in a program running is detected, You need to immediately leave the current _ Try block scope ), however, this avoids the additional overhead of "partial expansion. Let's look at an example! The Code is as follows:

# Include <stdio. h>

Void test ()
{
Puts ("hello ");
_ Try
{
Int * P;
Puts ("_ Try block ");

// Directly jump out of the current _ Try Scope
_ Leave;
P = 0;
* P = 25;
}
_ Finally
{
// Will it be executed here? Of course
Puts ("_ Finally block ");
}

Puts ("world ");
}

Void main ()
{
_ Try
{
Test ();
}
_ Partition T (1)
{
Puts ("_ blocks t ");
}
}

The program running result is as follows:
Hello
_ Try Block
_ Finally block
World
Press any key to continue

This is the function of the _ leave keyword, which is rarely used in programming. However, please note that if your program, especially in function modules with extremely complex business, uses the seh mechanism to ensure program reliability, if the Code contains a large number of goto statements and return statements, the binary program compiled from your source code will be very bad, the efficiency is also greatly affected. We recommend that you use the _ leave keyword to improve program performance.

Try-finally in-depth

Now, I believe we have a very comprehensive understanding of the try-finally mechanism. To further understand the benefits of the try-finally mechanism (of course, the hero, a Yu believes that, those who have written the driver on the Windows platform must be aware of the importance of the try-finally mechanism). Here is a specific example. Remember the simple routine that is implemented by setjmp and longjmp exception handling mechanisms in "Exception Handling Mechanism provided in 21st Windows operating system platform? Now, with the try-finally mechanism, we can easily avoid memory resource leakage and greatly improve the readability of program modules, reduce program bugs and other hidden risks caused by carelessness of programmers. The code re-implemented using seh is as follows:

# Include <stdio. h>
# Include <stdlib. h>

Void test1 ()
{
Char * P1, * P2, * P3, * P4;

_ Try
{
P1 = malloc (10 );
P2 = malloc (10 );
P3 = malloc (10 );
P4 = malloc (10 );

// Do other job
// An exception may be thrown during this period.
}
_ Finally
{
// Ensure that all resources are released in time
If (P1) Free (P1 );
If (P2) Free (P2 );
If (P3) Free (P3 );
If (P4) Free (P4 );
}
}

Void test ()
{
Char * P;

_ Try
{
P = malloc (10 );

// Do other job
// An exception may be thrown during this period.

Test1 ();

// Do other job
}
_ Finally
{
// Ensure resources are released
If (p) Free (P );
}
}

Void main (void)
{
_ Try
{
Char * P;

_ Try
{
P = malloc (10 );

// Do other job

// An exception may be thrown during this period.
Test ();

// Do other job
}
_ Finally
{
// Ensure resources are released
If (p) Free (P );
}
}
_ Partition T (1)
{
Printf ("caught an exception/N ");
}
}

Haha! The above code is simpler and more elegant than the Code implemented using the setjmp and longjmp mechanisms. This is the contribution of the try-finally statement.

Summary

(1) "under whatever circumstances, code in the Finally block area will be executed when it leaves the current scope", which is the core rule.

(2) the try-finally statement serves as an object-oriented destructor.

(3) goto statements and return statements. In other rare cases, break statements and continue statements may lead to program control flow out of the _ Try scope in an abnormal order, in this case, "partial expansion" of seh occurs ". Remember, "Local expansion" brings about a large overhead. Therefore, programmers should try to use the _ leave keyword to reduce unnecessary overhead.

Based on the in-depth explanation of seh Exception Handling Mechanism in these articles, I believe everyone is familiar with using seh for programming. In the next article, we will combine try-Finally t and try-finally mechanism for a comprehensive and comprehensive review. Let's continue!

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.