Write easy-to-debug-up VC code
A program design
To avoid errors, first start with a good design. For program design, consider two features of the program:
1 Simply
Most common errors are derived from unnecessary complex ingredients in programming. A good design should reflect the requirements of the problem itself, without having to add unnecessary features to deliberately pursue "satisfying future needs". In fact, simple and elegant design causing future needs than those complex design.
2 coupling
Decoupling sexuality is used to measure the dependence between different objects. Loose coupling procedures are easy to understand and implement, easy to test and maintain, and this program contains miscible, and error is also easier to discover and clear.
Two-programming style
Programming style is personal problems, with great randomness. A good programming style not only makes the code easy to understand, but also easy to debug. Good programming style includes:
1 clearly write code
If there is no need, try not to use the advanced features in the language because these features are not easy to understand and debug. Writing code is not easy to make mistakes using most of the programmers understand the language ingredients and easy to understand and maintain.
2 Writing a structure good code
The most basic debug information that can be obtained when the program crashes is the source code file, the line number and a call stack in the line. The calling stack is the most helpful part of the debugger, which provides the context that appears, which is a function call sequence with parameters. The better the code structure you write, the more information you can give you.
3 use good identifier
A good name can make your code more easily understood and maintained. The popular Hungarian NOTATION actually combines the meaning of the identifier and the expression method. Now, Hungarian nomenclature has a lot of limitations. The Hungarian nomenclature is too valued. The expression of a variable is incomplete. It is actually not delivered to how much useful information, which makes code difficult to read, difficult to maintain. A good named tradition is a scope of the variable to check its definition when needed, and clearly indicate that a variable is a global, partial or member data. Dependency variables are more useful and reliable than dependent Hungarian prefix.
A good name can generalize the meaning of the entity represented by the identifier in a usual language. When selecting classes, functions, and variables, you can consider the following principles:
Take a simple descriptive name, a good name briefly summarizes the meaning of this identifier representative.
Avoid shorthabing, short-handed identifier is difficult to read and memorize, try to use a complete word of mixed case.
Avoid the text of the similarity to avoid confusion.
Avoid adopting general or random names, but should use the actual name. To take a bitmap button from the button class, take a cbitmapbutton instead of CMYButton.
4 use simple statement line
In the VC, one line can write multiple statements. But debugging is facing, too complicated, difficult to debug. Therefore, from the perspective of debugging, each statement should be in a row.
5 use unified arrangement
The unified arrangement makes the definition and statement of the class, variables more obvious.
6 Clear writing with parentheses
You don't necessarily remember the priority and combination law of various operators, and use excess parentheses does not affect the compiled code. So if you can't determine if you need parentheses, add it.
7 use good notes
Using a good comment allows your code to be incapable, and it is easy to read, easy to understand and maintain.
I should pay attention to the problem when writing programs
1 Take advantage of VC features
The following techniques can be used to take advantage of the characteristics of the VC compiler:
(1) Use const instead #define to create constants;
(2) Use enum instead #define to create a constant collection;
(3) instead of #define with the inline function;
These three techniques use C instead of C pre-pre-processed. The problem with pretreatment is that the compiler does not know if the compiler does something made by the preparation, so it cannot be used to check the errors and inconsistent places. The pre-processed name is not in the symbol table, so it cannot be used to check the pretreatment constant. Similarly, the preprocessing macro is compiled and cannot be tracked with debug tools. The compiler fully understands the const, enum, and inline statements, so that the problem will be warned when compiling. (4) Use new and delete instead of Malloc and Free; but preprocessing plays an important role in many commission code. Debug code often needs to get different behaviors from non-debug code, and the most effective way is to let preprocesses create different code for debugging.
In terms of creating objects, types of security and flexibility. Use new / delete better than Malloc / Free. In addition, New can be overloaded, providing greater flexibility. (5) Instead of STDIO with an input and output stream (iostreams).
Use C input and output streams (<< and >>) without using C standard input and output libraries (PrintF / Sprintf and Scanf / SSCANF) are conducive to security and scalability. From the perspective of debugging, the biggest problem with standard input and output functions is that the compiler cannot detect any type detection on the control flow parameters, and any problem with the input and output stream can be detected at compile.
2 use header files
To declare all shared external symbols in the header file, and reserve the parameter name in the function prototype. Put all shared definitions in the header file, do not see the extern keyword in the .cpp file.
3 initialization variables
Be sure to initialize them before using variables. Use variables will definitely generate errors before initialization. You usually do not need to initialize the object, and the pair of data should be initialized in the constructor. It must be explicitly initialized for the arrays and data structures allocated in the stack and the stacks. For objects, each need to initialize the data should be initialized. Because the use of variables are checked by an optimizer, the local variables that are not initialized are detected, and the release version is better than the debug version.
4 use Boolean expressions
C Boolean type: Bool, value is True and False, size is one byte.
Windows programs typically use the BOOL type. Defined as follows:
Typedef int BOOL;
#define false 0
#define True 1
In C , a Boolean expression is false if it is 0, and others are true. Therefore, the Boolean expression should check if the counterfeit rather is true.
5 use handles and pointers
When you initialize a pointer, or let it point to an effective memory address, or set to 0 (empty pointer), avoid the pointer to the invalid address. Recycling this pointer when the object refers to the pointer, and processes it when the pointer is released before the pointer is released. The processing of the handle is the same as the pointer.
6 Use reference instead of pointer to do parameters
The parameters that use the pointer to function can pass an empty pointer, which is flexible, but it is also easy to forget to initialize the pointer. The reference is an alias of the object, it must be associated with a valid object, there is no reference to empty and no initialization. When you receive a reference parameter in a function, it is certain that this is a valid object. The quote for the program is more robust than the parameters for the pointer.
7 Mandatory Type Conversion (CAST)
When the mandatory type conversion of the data type, the corresponding constructor or conversion function will be called to create a new type of temporary object. The correct type conversion of the pointer eliminates a compilation error, but does not change the pointer. Forced type conversion destroys the functionality of the compiler for type inspection, which is the most effective mechanism for compilers to find errors. To ensure security, each forced type conversion requires manual type check. To try to avoid mandatory type conversion, you can: avoid using polymorphism data types; use a more wide base class; provide special access functions; let the compiler implicitly handled type conversion. 8 use constructor and destructor
The constructor needs to allocate memory, create a resource or open file, which is not always successful. The constructor does not return a value, and there is no way to display an error directly. A common method (used in many MFC classes) is to create object creation into two steps: first step, let constructor initialize the object in a way that will not be wrong; second step, let some initialization functions (such as INIT or OPEN is complete, this step may be wrong. Another method is to use an exception in the constructor: the first step is initialized in a way that does not have an error; the second step is to initialize the object with the code that may be erroneous in the TRY segment; the third step is processed in the CATCH code abnormal. If an exception occurs, the allocated resource will be cleared in the constructor and throw an exception again.
A key detail of exception handling is an exception thrown during the stack to terminate the entire application. When processing an exception, the destructive function is often called, so the destructive function is easily error, and must ensure that the exception of the destructive function is processed in the destructor. To ensure that the analytical function of the base class is a virtual function. In this way, even if the object is a pointer to the base class, the secting function of the derived class will also be called. Otherwise, it will cause resource leakage.
(Resource Leak)
.