C ++ FAQ Lite [17] - Exceptions and Error Processing (Update)

zhaozj2021-02-08  233

[17] Abnormal and error handling (Part of C FAQ Lite, Copyright © 1991-2001, Marshall Cline, Cline@parashift.com)

体,, nicrosoft @ sunistudio.com (East day production room, East day document)

FAQS in section [17]:

[17.1] What methods pass / carat / throw to improve software quality? [17.2] How to deal with the failure of constructor? [17.3] How to deal with the failure of the destructor? [17.4] If the constructor will throw an exception, how should I handle resources? [17.5] How do I change the character string length of the character array to prevent memory leakage?

[17.1] What methods pass / carat / throw to improve software quality?

[Recently Created (on 7/00). Click Here To Go To The Next Faq in The "Chain" of Recent Changes

]

By excluding one reason for using the IF statement.

Instead of Try / Catch / Throw is to return a return code (sometimes referred to as an error code), the caller is explicitly tested through a conditional statement such as if IF. For example, Printf (), scanf () and malloc () are working in this way: the caller is assumed to determine whether the function is successful.

Although returning code technology is sometimes the most appropriate error handling technology, an annoying effect of adding unnecessary IF statements will produce.

Quality Digestion: It is well known that the error may include more than ten times the other type of statement. Therefore, when you have the same, if you can eliminate the conditional statement from your code, you will get a more robust code. Delayed sales: Since the conditional statement is a branch point, they are related to the number of test conditions when the white box method is tested, so unnecessary conditional statements will increase the total amount of tests. If you have not gone through each branch point, then you will have an instruction that has not been performed in the test until the user / customer discovers it, it is bad. Increase development costs: Unnecessary control flow complexity adds to search for bugs, repair bugs, and testing.

Therefore, relative to the incorrect error by returning code and IF, using TRY / CATCH / THROW produces less bug, lower development costs and faster code. Of course, if your team doesn't have any experience using try / catch / throw, you may want to use it on a toy project to determine what you are doing - taking the weapon to the real gun Before the front line, you should always exercise.

[TOP | BOTTOM | Previous Section | Next Section]

[17.2] How to deal with the failure of constructor?

[Recently Fixed TYPO ("ITS" vs. "it's") THANKS TO WES BEMONT (ON 4/01). Click Here to Go To The Next FAQ in The "Chain" of Recent Changes

]

Throw an exception.

The constructor does not return the type, so it is impossible to return an error code. Therefore, the throwing exception is the best way to mark the failed constructor.

If you don't or want to use an abnormality, there is a way. If the constructor fails, the constructor can bring the object into a "zombie" state. You can set an internal status bit to make the object, even if it is technically, it is still alive. Then join a query ("Prosecutor") member function, so that the user can determine the object by checking this "zombie" to determine whether the object is really alive or has become a zombie (that is, a "living dead object"). You may want to have another member function to check this zombie, and when the object is not really alive, perform a NO-OP (or more annoying like Abort ()). This is the best way to do this is really unpleasant, but if you can't (or don't want) to use an abnormality, this is the best way. [TOP | BOTTOM | Previous Section | Next Section]

[17.3] How to deal with the failure of the destructor?

[Recently Created (on 7/00). Click Here To Go To The Next Faq in The "Chain" of Recent Changes

]

Write a message to the log file. Or call the Tilda aunt. But don't throw an exception!

Here is why (buckle your seat belt):

The rule of C is absolutely not to throw an exception from the destruction function when another exception is called "stack unwinding". For example, if someone wrote Throw foo (), the stack will be expanded, and all the stacks between throw foo () and} Catch (foo e) {are popped up. This is called a stack unwinding (STATCK unwinding)

At the stack show, all local objects in the stack page will be destructed. If one of those destructor throws an exception (assuming it throws a BAR object), the C runtime system will be unresinable: BAR should ignore the BAR and end? You should ignore the foo and look for} catches (bar e) {? No good answer - each option will lose information.

So C language guarantees, when in this, Terminate () will be called to kill the process. Sudden death.

A simple way to prevent this situation is not to throw an exception from the destructive function. But if you really want to be smart, you can say that when you process another abnormal process, don't throw an exception from the destruction function. However, in the second case, you are in a difficult situation: the destructor itself requires both code processing to throw an exception, but also to handle some "other things", what happens when the caller does not detect the error when the array is detected? Guarantee (may throw an exception, or some "other things"). So the complete solution is very difficult to write. So do some "other things". That is, don't throw an exception from the destructive function.

Of course, these words should not be "certified" because there are always some cases of this rule. But at least 99%, this is a good rule.

[TOP | BOTTOM | Previous Section | Next Section]

[17.4] If the constructor will throw an exception, how should I handle resources?

Each data in the object should clean yourself.

If the constructor throws an exception, the destructive function of the object will not run. If your object needs to undo some already doing actions (if you assign memory, open a file, or lock a certain semaphore), these needs to be revoked must be remembered by a data within the object.

For example, the assigned memory is assigned to a "smart pointer" member object fred, not the memory to the memory that is not initialized. This will delete the Fred object when the intelligent pointer is dying. Standard AUTO_PTR is an example of this "smart pointer" class. You can also write your own reference count smart pointer. You can also use smart pointers to point to objects on disk records or other machines. [TOP | BOTTOM | Previous Section | Next Section]

[17.5] How do I change the character string length of the character array to prevent memory leakage?

[Recently Rewrote The Last Half (ON 7/00). Click Here to Go To The Next Faq in The "Chain" of Recent Changes

]

If you have to do a string, don't use the char array because the array will bother. You should use some objects that are similar to string classes.

For example, suppose you want to get a copy of a string, modify this copy, then add other strings at the end of the modified copy of the string. The character array method will be like this:

Void Usercode (const char * s1, const char * s2) {

// Make a copy of S1:

Char * copy = new char [STRLEN (S1) 1]; STRCPY (COPY, S1);

// Now we have a pointer to the memory that is allocated freely stored.

// W We need to prevent memory leakage with a TRY block:

Try {

// ... n Now we will move this copy ...

// Add S2 to the end of the modified COPY:

// ... [Heavy Distribution COPY] ...

Char * COPY2 = New Char [Strlen (Copy) Strlen (S2) 1]; STRCPY (COPY2, COPY); STRCPY (COPY2 STRLEN (COPY), S2); Delete [] Copy; Copy = COPY2;

// ... Finally, we will arbitrarily copy again ...

} Catch (...) {delete [] copy;

// Get an exception, prevent memory leakage

Throw;

/ / Re-throw the current exception

} DELETE [] COPY;

// Do not get an exception, prevent memory leakage

}

Like this use char * S is monotonous and error occurs. Why don't you use a string class? Your compiler may provide a string class, and it may be faster than your own CHAR * S, of course, is also simpler, safer. For example, if you use the character string of the standardization committee std :: string, your code looks like this:

#include

/ / Let the compiler find std :: string class

Void Usercode (Const std :: string & s2) {std :: string copy = s1;

// Make a copy of S1

// ... Now we will move this copy ...

COPY = S2;

// a Add S2 to the modified copy end

// ... Finally, we will arbitrarily copy again ...

}

There are only two lines of code in the function body, and there are 12 lines of code in the previous example. Save from memory management, but there are some from our unnecessary to call Strxxx () routines. There are some focus here:

Since Std :: String automatically processes memory management, when we grow strings, we don't need to write any code that allocated memory prior. Since Std :: String automatically handles memory management, do not need delete [] at the end. Since std :: string automatically processes memory management, in the second example, the TRY block is not required, even if someone will throw an exception at someone. [TOP | BOTTOM | Previous Section | Next Section]

E-mail the author [C FAQ Lite | Table of Contents | Subject Index | About The Author | © | Download Your Own Copy] Revised Apr 8, 2001

转载请注明原文地址:https://www.9cbs.com/read-2068.html

New Post(0)