Exception Handling in Depth

xiaoxiao2021-04-10  480

Exception Handling in Depth, Part 1 listened to a friend of Intel on MCPD to talk about his views on C Exception Handling. The general view is: [1] Use exception handling to lose performance [2] to avoid using Exception Handling and Return Error Value. However, in the boundary of the module, in order to cover the Exception on THROW, use Exception Handling. At that time, many people expressed his views. I also hold opposition: [1] Performance problem. The friend took out the VC6 data to speak, indeed, using VC6, after opening Exception Handling, the performance of Happy Path has also been affected (Unhappy Path is a small probability event, so in most cases its performance problem is not It is worth discussion). However, VC6 is just a version of a compiler. It is also a more old version. Its Exception Handling implementation is SEH, which seems to have entered the kernel after several APIs, it is indeed slow. But we can't be "one glability" in VC6. It is generally considered the best compiler on the Windows platform to be Intel C (very strange this friend from Intel, how do you not analyze your own compiler, and analyze an antique compiler of MS). In addition, VC7, GCC and BCC are also very good. What is the performance of C Exception Handling, you can see the related content in ISO / IEC TR 18015 "Technical Report On C Performance". I roughly summarize: Exception-handling can have 2 categories. The first class is implemented in insertion code. It has the ability to have a thousand autumn in other Error Handling methods. In fact, the one variety of such variants is the compiler to automatically systematically add Error Return. Value and deal with these Return Value, so performance characteristics, but only avoids handwritten troubles and leaks caused by bugs. Category 2 is a surfacitor, there is a certain space overhead, but time performance is better than other Error Handling methods. Zero Overhead can be made on Happy Path. (Compared to the same, Error Return Value is not Zero Overhead on Happy Path, because even if it is also possible on Happy Path. Although this IF statement does not take up, IF The statement is the big enemy of the pre-execution / branch prediction. Error Return Value will bring countless IF, and performance loss caused on modern CPU is very serious. [2] Use problems. My point of view and this friend In contrast. I tend to use Exception. Reason, I mentioned in the previous blog (http://spaces.msn.com/members/wesleybao/blog/cns !1p0i3youkrgnwt0uyav1fmog !594.ntry), the method of using Error Return Value is The 2 different execution dimensions of HAPPY PATH and Unhappy Path are covered with one execution dimension, which is better than trying to pack a ball with a flat paper, it must be covered with crumpled, extremely unity. Software A central topic of the design is coupled. We should pursue loose coupling as much as possible, and separate things that are not coherent.

These two non-coherent paths in HAPPY PATH and UNHAPPY PATH are tight, wrapped together in ERROR RETURN VALUE, or other methods, and only use Exception as an Error Handling mechanism to unprogerse these two paths. For a simple example: A = (b c) * (D-E) / f This simple statement, in fact, only HAPPY PATH. Each of the facts may be wrong. For example, the division may except 0, addition and multiplication may overflow, and so. Moreover, if , *, -, / all overloaded operators, Abcdef is not a number but a custom object, and other errors may also occur. Then, in the Production Code (so-called Production Code, it is not allowed to ignore the error handling, relatively relative to Toy Code), how to write this expression? If you use anomalous, it is very simple: try {= (b c) * (de) / f;} catch (Exception & E) {// Error Handling Here} If you use Error Return Value, you can trouble TMP1 = B C; if (there is error) {report error} else {TMP2 = de; if (there is error) {report error} else {TMP3 = Tmp1 * TMP2; if (there =) {report error} else {a = TMP3 / F IF (There IS Error) {report error} else {// a is the result;}}}} If this expression is more complicated, what will be? In fact, ERROR RETURN VALUE (or ERROR OUTPUT Parameter) can only be used for Procedural Programming. For other paradigm, such as Functional Programming like Lisp, ERROR RETURN VALUE cannot be used. Even in Procedural Programming, using Error Return Value will also cause 90% of all code to be error transfer and processing code, only 10% is the real job code. In the Error Handling mechanism currently invented, I am afraid that only Exception Handling is the true scalable Error Handling mechanism. Still returning to the friend's point of view, step by step, even if you put a good Intel compiler and don't have money, high-quality GCC is not used, it is equipped with VC6. It is used to use, but also causing Exception, a person who gives the code has caused great trouble and brought a bug (see the ERROR RETURN VALUE version of the Error Return Value) A = (B C) * ( DE) / f, as long as you accidentally miss an IF, it is a potential bug). However, since the abnormality throws up in the boundary (such as some third-party libraries will throw it), then the compiler's Exception Flag must also open, so the performance loss is not avoided, the development efficiency is lost.

Not all of all suffering, but what is the benefits? Sometimes I am quite wondering, why some people are so hard, there is no need to have something to do, and I prefer to find trouble? And I still asked everyone to come from find trouble, it seems that it is not too lazy. My point is: [1] Use exception as an Error Handling mechanism within the module [2] module with a C API (Return Error Value), but use the C API to be a Type-Safe package, and put Error Value Change to Exception. Of course, after the C ABI standard is out and is implemented by the compiler manufacturer, the boundary can also use Exception. [3] Only an exception is used for anomalies, and an exception processing code does not appear in the normal execution path. [3] The meaning needs to explain it. For example, there is a function, Bool FileExists (Const Char * file); Obviously regardless of the file store does not exist on the normal execution path. The use of this function is to check if the file exists, in other words, from the perspective of DBC, this function does not have "file existence" precondition, then if the file does not exist, it is obviously not to throw Exception. Assume that the internal operation of this function needs to be allocated, the memory allocation fails, then obviously throwing Exception. Processing logic should not be coupled with Exception in the normal execution path. The next time I have time to talk about how to make C Exception mechanisms to implement the PrintStackTrace () method as Java or C #.

Exception Handling In Depth, Part 2 SEH and C Exception SEH are Windows error handling mechanisms to process fatal errors such as Access Viological. In general, if your program will throw structured abnormality, most of them are bugs in the program. Therefore, before the product release, the program should not be connected to structured, which is Crash, so that BUG is exposed as soon as possible. The C Exception is designed for the error handling of the program itself, which can only take the exception thrown through the throw keyword in the program. There is no power for the problems such as Access Violation, Division By Zero. From a conceptual, SEH and C Exception are very different from two yards, each with different applicable situations. However, on the Windows platform, the compiler is very convenient to implement C Exception through SEH. It is worth mentioning that VC6 has a bug on an abnormal asynchronous implementation (/ EHA), and use caratch (...) in some cases, it can also receive structured abnormalities. Sometimes the Debug version can catch, the release version is not. If you compile with / gx, sometimes you can in the Debug / Release version. If some optimized options have been opened, it may not. If you choose to use an abnormal synchronization implementation (/ EHS), there will be no such problem. This bug is fixed in VS2005, whether it is selection synchronization or asynchronous implementation, Catch (...) only connects C exception, no matter how unuso structured. If you do so abnormally into C anomaly (against this, because SEH and C abnormal processing are completely two-code things), you can use the _SET_SE_TRANSLATOR function. However, only an abnormal asynchronous implementation (/ EHA) can ensure proper transformation. To talk about it, to evaluate the performance of VC6 exception, it is best to evaluate the synchronous and asynchronous implementation. How to make C exceptions also with Stack TRACE JAVA and C #'s Exception are Trove with Stack TRACE, it is very easy. C Exception is not. So, I saw that many projects have developed a strict debug log / trace specification, requiring TRACE in the entrance / export, and a purpose is to push the Stack TRACE from the LOG. But doing this is more troublesome, to insert a lot of logs in the code. It is better to do Error Handling with Exception, and then let Exception take Stack TRACE to save this. Let's talk about how to generate STACK TRACE. A cross-platform method is manually in the stack to save iconic strings, and even manually maintain a stack and operate this stack in the constructor of the anomaly class. However, this is not much better than the method of logging, and the exception handling of the program meets some agreements, not a good way. The provincial approach is not cross-platform. MINIDUMPWRITEDUMP can be called to generate mini dump on Windows. MINI DUMP contains complete STACK TRACE information. Stack information can also be obtained by APIs such as Stackwalk / Stackwalk64. You can also directly access the EBP and go to the first floor of the stack. Core DUMP can also be generated on the UNIX platform, and there will be a API similar to STACKWalk. If Symbol strip is dropped, then Stack Trace only has no name, not intuitive.

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

New Post(0)