Effective C ++ 2e Item46

zhaozj2021-02-11  205

Terms 46: I would rather compilation and link error, don't run error

In addition to the homework, the C will throw an abnormality (for example, the memory consumption --- see clause 7), the concept of runtime is wrong, and it is like a relationship between C . No underflow, overflow, divided into zero inspection; no array croucher check, and so on. Once the program has compiled and link, you have to rely on yourself ---- all the consequences are at your own risk. This is very like skydiving, some people have found excitement, others scared to fall into disabled. The motivation behind this idea is of course in efficiency: no runtime check, the program will be smaller faster.

Handling such things have another different way. Some languages ​​such as SmallTalk and Lisp are usually only checked for minimal errors during the compilation link, but it provides a powerful runtime system to handle errors during execution. Not like C , these languages ​​are almost interpretable, while providing additional flexibility, they also bring performance loss.

Don't forget that you are using C . Even if the method of SMALLTALK / LISP is found, it is also attractive, but also forgets them. It is often said that we must adhere to the party's route. Now, its meaning is to avoid running error. As long as it is possible, let the error check when returned from the runtime, or ideally, compile.

The benefits of this method are not only the size and speed of the program, but also reliability. If the program does not generate an error message through compilation and link, you can confine that there is no error in the program and the linker to check any errors, this is (Of course, another possibility is that the compiler or linker has problems, but don't take this possibility to trouble us.)

For runtime errors, the situation is large. In a certain run, there is no runtime error, you can confirm that there will be no errors in different running periods? For example, in another run, you do things in different order, or use different data, or run longer or shorter, and so on. You can keep taking your own procedure until the face is purple, but you still can't overwrite all the possibilities. Thus, the error is discovered when the runtime is more reliable than checking the error during the compiled link.

Typically, you can do a small change in your design, you can eliminate possible runtime errors during compilation. This often involves adding new data types in the program (see Terms M33). For example, suppose to write a class to indicate the date in the time, the initial approach may like this:

Class Date {public: Date (int day, int month, int year);

...

}

Preparing to implement this constructor, one of the problems faces the legality check for DAY and MONTH values. Let's take a look. For the value passed to Month, how can you avoid legality checking it?

An obvious way is to use enumeration types without integers:

ENUM MONTH {Jan = 1, Feb = 2, ..., NOV = 11, DEC = 12};

Class Date {public: Date (int Day, month, int year);

...

}

Unfortunately, this will not be exchanged, because the enumeration type does not need to initialize:

Month M; DATE D (22, M, 1857); //m is uncertain

So, the DATE constructor still has to verify the value of the MONTH parameter.

I want to avoid the runtime check, but also guarantee enough security, you have to use a class to represent Month, you have to ensure that only legal Month is created: Class Month {public: static const monrth Jan () {Return 1;} static const month feb () {return 2;} ... static const month dec () {return 12;}

INT asint () const // For convenience, Month {Return Monthnumber;} / / can be converted to int

Private: month (int number): MONTHNUMBER (Number) {}

Const int MONTHNUMBER;

Class Date {public: Date (int day, const month, int year); ...};

This design is comprehensively identified in several ways. First, the MONTH constructor is private. This prevents users from creating new Month. It can only be used by the object returned by the still member function of Month, plus their copy. Second, each Month object is const, so they cannot be changed (otherwise, many places will not help to convert January into June, especially in the northern hemisphere). Last, the only way to get the Month object is to call functions or copy existing Month (through implicit MONTH copy constructor --- see clause 45). This way, you can use the month object anywhere; don't worry that there is no initialized object inadvertently. (Otherwise there may be a problem. Terms 47 have been described)

With these classes, users can hardly designate an illegal month, even impossible ---- If there is no such abominable situation:

MONTH * PM; / / Define the pointer uninitialized

DATE D (1, * pm, 1997); // Use a pointer that is not initialized!

However, this situation is another problem, that is, the result is unsure of the value that is not initialized. (See Terms 3. Look at the feelings of "Unsure Behavior" regret, I have no way to prevent or check this heresy. However, if this situation will never happen, or if we don't consider the behavior of the software, the Date constructor can exempt the legitimacy check. On the other hand, the constructor must also check the legality of the DAY parameter - how many days in September, April, June and November?

Date's example will replace it with compile time when checking. You may want to know when you can check when using a link. In fact, don't do this. C uses a linker to ensure that the required functions are only defined (see Terms 45, "need" one function will bring anything). It also uses the linker to ensure static objects (see Terms 47) are only defined once. You can use the same method using the same method. For example, clause 27 illustrates that for a function of an explicit declaration, the linker check is useful if you want to disable it.

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

New Post(0)