In C ++, there are three types of loop statements: For, while, and do... while, but in general applications for loop, we may use for and while to have more, do... while is relatively not valued. However, when I recently read the code of our project, I found some clever usage of do... while, not for loop, but for others to improve code robustness.1. Do... while (0) eliminates the GOTO statement. Generally, if you want to allocate some resources in a function, and then exit the function if an error occurs during execution, release the resources before exiting, our code may be like this: Version 1
Bool execute () { // Allocate resources Int * P = new int; Bool Bok (true );// Execute and handle errors Bok = func1 (); If (! Bok) { Delete P; P = NULL; Return false; } Bok = func2 (); If (! Bok) { Delete P; P = NULL; Return false; } Bok = func3 (); If (! Bok) { Delete P; P = NULL; Return false; } //.......... // The execution is successful. Release the resource and return Delete P; P = NULL; Return true;
} The biggest problem here is code redundancy. Every time I add an operation, I need to handle the corresponding error, which is very inflexible. So we thought of Goto: Version 2 Bool execute () { // Allocate resources Int * P = new int; Bool Bok (true );// Execute and handle errors Bok = func1 (); If (! Bok) goto errorhandle; Bok = func2 (); If (! Bok) goto errorhandle; Bok = func3 (); If (! Bok) goto errorhandle; //.......... // The execution is successful. Release the resource and return Delete P; P = NULL; Return true; Errorhandle: Delete P; P = NULL; Return false;
} Code redundancy is eliminated, but we have introduced a subtle GOTO statement in C ++. Although correct use of goto can greatly improve the flexibility and simplicity of the program, but too flexible things are often very dangerous, it will make our program confused, so how can we avoid using goto statements and eliminate code redundancy? Please refer to do... while (0) loop: Version3
Bool execute () { // Allocate resources Int * P = new int;Bool Bok (true ); Do { // Execute and handle errors Bok = func1 (); If (! Bok) break; Bok = func2 (); If (! Bok) break; Bok = func3 (); If (! Bok) break; //..........
} While (0 ); // Release resources Delete P; P = NULL; Return Bok;
} "Pretty !", You just need to read the code... 2 do... while (0) in macro definition) If you are a C ++ programmer, I have a reason to believe that you have used or been in touch with, at least heard of MFC, afx in MFC. in the H file, you will find that many macro definitions use do... while (0) or do... while (false), for example: # Define afxassume (Cond) do {bool _ afx_condval = !! (Cond); Assert (_ afx_condval); _ analysis_assume (_ afx_condval);} while (0) When we look at it, we will find it strange. Since the loop is only executed once, what is the significance of this seemingly redundant do... while (0? Of course! To make it clearer, we use a simple macro to demonstrate it: # Define safe_delete (p) do {Delete P; P = NULL} while (0) Assume that do... while (0) is removed here ), # Define safe_delete (p) delete p; P = NULL; The following code: If (null! = P) safe_delete (P) Else... do... There are two problems, 1) Compilation fails because the If Branch has two statements and the else branch does not have the corresponding if statement. 2) If no else exists, the second statement in safe_delete will be executed forever regardless of whether the if test passes or not. You may find that in order to avoid these two problems, I don't have to use this confusing do... while. I can simply use {} to enclose it. # Define safe_delete (p) {Delete P; P = NULL ;} Indeed, the above problem does not exist, but I think for C ++ programmers, adding points after each statement is a common habit. In this way, the following code: If (null! = P) safe_delete (P ); Else... do... The else branch cannot be compiled (the reason is the same as above), so using do... while (0) is a good choice. Maybe you will say that the habit of our code is to add {} after each judgment, so there will be no such problem, so do... while is not required, such: If (...) { } Else { } It is true that this is a good programming habit that should be promoted, but such macros generally appear as part of the library. For the author of a library, all he has to do is to make his library universal and robust. Therefore, he cannot have any assumptions about the database users, such as coding specifications and technical level. |