Replacing macros with Inline:
1. inline functions can be debugged at runtime, but macro definitions cannot;
2. the compiler checks the parameter types of inline functions for security or automatically converts the types (same as normal functions), but the macro definition does not;
3. inline functions can be member variables of the callback class, while macro-defined functions cannot;
4. Declare the member functions defined at the same time in the class and convert them into inline functions automatically.
Article (1)
Inline functions and macro definitions
In C, a commonly used pre-processing statement # define is used to replace a function definition. For example:
# Define MAX (a, B) (a)> (B )? (A) (B ))
This statement makes every place in the program where the MAX (a, B) function is called by the expression (a)> (B) after the macro definition )? (A) (B) replace.
The writing format of macro-defined statements is overemphasized. There cannot be spaces between MAX and parentheses. All parameters must be
In brackets. However, it is still troublesome:
Int a = 1, B = 0;
MAX (a ++, B); // a is added twice
MAX (a ++, B + 10); // a is added once
MAX (a, "Hello"); // compare int and string by mistake, no parameter type check
The evaluate of the MAX () function produces different side effects because the values of the two parameters are different.
The value of MAX (a ++, B) is 2, and the value of a is 3;
The value of MAX (a ++, B + 10) is 10, and the value of a is 2.
If it is a common function, MAX (a, "HellO") will be checked by the function call, but this will not be rejected by compilation because the two parameter types are different. Fortunately, you can use an inline function to get the efficiency of replacing all macros, all foreseeable states, and check the type of common functions:
Inline int MAX (int a, int B)
{
Return a> B? A: B;
}
1. Differences between inline functions and macros:
Traditional macro-defined functions may cause some trouble.
Ex:
# Define F (x) x + x
Void main () {int I = 1; F (I ++ );}
Here, x will be added twice.
Inline functions are automatically added to the Code by the compiler when they are used.
The use of inline functions improves the efficiency (saving a lot of function call Assembly Code such as call and ret ).
2. Use of inline functions:
All functions defined in the class declaration will be automatically considered as inline functions.
Class ()
{
Void c (); // not a inline function;
Void d () {print ("d () is a inline function .");}
}
If you want to define a global function as an inline function available, the inline keyword.
Inline a () {print ("a () is a inline function .");}
Note:
Complex operations in inline functions are not inline. Such as loop and recursive call.
Summary:
Defining simple and short functions as inline functions improves efficiency.
Article (2)
8.5.1 replacing macro code with Inline
C ++ supports function inline to improve the function execution efficiency (speed ).
In C Programs, macro code can be used to improve execution efficiency. Macro code itself is not a function, but it is used as a function. The pre-processor replaces the function CALL by copying macro code, saving the process of parameter pressure stack, generating CALL calls for the assembly language, returning parameters, and executing return, thus improving the speed. The biggest disadvantage of using macro code is that it is prone to errors, and The Preprocessor often produces unexpected marginal effects when copying macro code. For example
# Define MAX (a, B) (a)> (B )? (A): (B)
Statement
Result = MAX (I, j) + 2;
Will be interpreted
Result = (I)> (j )? (I): (j) + 2;
Because the operator '+' has a higher priority than the operator ':', the preceding statement is not equivalent to the expected
Result = (I)> (j )? (I): (j) + 2;
If you rewrite the macro code
# Define MAX (a, B) (a)> (B )? (A): (B ))
It can solve the error caused by priority. However, the modified macro code is not foolproof, for example, the statement.
Result = MAX (I ++, j );
Will be interpreted
Result = (I ++)> (j )? (I ++): (j );
For C ++, the use of macro code has another drawback: The operation class of private data members is not allowed.
Let's take a look at how C ++'s "function inline" works. For any inline function, the compiler puts the declaration of the function (including the name, parameter type, and return value type) in the symbol table ). If the compiler does not find an error in the inline function, the code of the function is also placed in the symbol table. When calling an inline function, the compiler first checks whether the call is correct (for a type security check or automatic type conversion, of course, all functions are the same ). If correct, the code of the inline function replaces the function call directly, saving the overhead of the function call. This process is significantly different from preprocessing because the pre-processor cannot perform type security checks or perform automatic type conversion. If the inline function is a member function, the object address (this) will be placed in a suitable place, which is not implemented by the Preprocessor.
The function inline mechanism in the C ++ language provides both macro code efficiency and security, and allows you to operate data members of the class freely. Therefore, in C ++ programs, we should replace all macro code with inline functions. I am afraid assert is the only exception. Assert is a macro that only works in the Debug version. It is used to check the situation where "no" occurs. In order not to cause any difference between the Debug and Release versions of the program, assert should not produce any side effects. If assert is a function, the Debug version differs from the Release version because the function call may cause changes in memory and code. So assert is not a function, but a macro. (See section 6.5 "using assertions ")
8.5.2 programming style of inline functions
The keyword inline must be put together with the function definition body to make the function inline. It does not work unless you put inline before the function declaration. The following function Foo cannot be an inline function:
Inline void Foo (int x, int y); // inline is only put together with the function declaration
Void Foo (int x, int y)
{
...
}
The following function Foo becomes an inline function:
Void Foo (int x, int y );
Inline void Foo (int x, int y) // put inline together with the function definition body
{
...
}
Therefore, inline is a "keyword used for implementation", rather than a "keyword used for Declaration ". Generally, you can read the declaration of a function, but cannot see the definition of a function. Although the inline keyword is added before the declaration and definition body of inline functions in most textbooks, I don't think inline should appear in the declaration of functions. Although this detail does not affect functions of functions, it reflects a basic principle of high quality C ++/C programming style: Declarations and definitions cannot be confused, the user does not need to know whether the function needs to be inline.
The member functions defined in the class declaration will automatically become inline functions, for example
Class
{
Public:
Void Foo (int x, int y ){... } // Automatically become an inline function
}
Putting the definition body of the member function in the class declaration can bring convenience in writing, but it is not a good programming style. The above example should be changed:
// Header file
Class
{
Public:
Void Foo (int x, int y );
}
// Definition file
Inline void A: Foo (int x, int y)
{
...
}
8.5.3 use inline with caution
Inner join can improve the execution efficiency of functions. Why not define all functions as inline functions?
If all functions are inline functions, do you still need the keyword "inline?
Inline is at the cost of code expansion (replication). It only saves the overhead of function calls and improves the function execution efficiency. If the execution time of code in the function body is higher than the overhead of function calling, the efficiency gains will be little. On the other hand, every call to an inline function must copy the code, which will increase the total amount of code in the program and consume more memory space. Inline is not recommended in the following cases:
(1) If the code in the function body is long, using inline will cause high memory consumption.
(2) If there is a loop in the function body, the execution time of the Code in the function body is longer than the overhead of the function call.
Class constructor and destructor are easy to misunderstand that using inline is more effective. Be careful that constructors and destructor may hide some behaviors, such as secretly executing constructors and destructor of base classes or member objects. Therefore, do not place the constructor and destructor definitions in the class declaration.
A good compiler will automatically cancel the inline that is not worthwhile based on the definition body of the function (this further demonstrates that inline should not appear in the declaration of the function ).
8.6 experiences
The heavy load, inline, default parameters, and implicit conversion mechanisms in the C ++ language present many advantages, but these advantages are hidden. Just like people's diet, less food and overeating are not advisable and should be right. We need to treat the new mechanisms of C ++ dialectically and use them appropriately. Although this will make us spend more time in programming, less time, but this is the art of programming.
Chapter 2 class constructor, destructor, and assignment function
Constructors, destructor, and assignment functions are the most basic functions of each class. They are so common that they are easy to paralyze. In fact, these seemingly simple functions are as dangerous as the sewers without the top cover.
Each class has only one destructor and one value assignment function, but it can have multiple Constructors (including one copy constructor, and others are called normal constructor ). If you do not want to write the above functions for any class A, the C ++ compiler will automatically generate four default functions for Class A, such
A (void); // default no-parameter Constructor
A (const A & a); // default copy constructor
~ A (void); // default destructor
A & operate = (const A & a); // default value assignment function
This is confusing. Why do programmers need to write functions automatically?
The reason is as follows:
(1) If "Default non-parametric constructor" and "Default destructor" are used, the chance of independent "initialization" and "Clearing" is abandoned, the good intentions of C ++ inventor Stroustrup are in vain.
(2) Both the "Default copy constructor" and "Default Value assignment function" are implemented by "bit copy" instead of "value copy, if the class contains pointer variables, these two functions are doomed to go wrong.
For C ++ programmers who have not suffered enough, if he says it is easy to write constructor, destructor, and assignment function, he does not have to worry about it, indicating that his understanding is superficial, the level needs to be improved.
This chapter takes the design and implementation of the String class as an example to explain in depth the principles ignored by many textbooks. The String structure is as follows:
Class String
{
Public:
String (const char * str = NULL); // common Constructor
String (const String & other); // copy the constructor
~ String (void); // destructor
String & operate = (const String & other); // value assignment function
Private:
Char * m_data; // used to save strings
};
========================================================== ========================================================== ======================================
During program compilation, the compiler replaces the calling expression of the inline function in the program with the function body of the inline function. Obviously, this method will not cause a transfer-back problem. However, because the code in the function break is replaced by the program during compilation, the amount of target program code will be increased and the space overhead will be increased, in terms of time consignment, it is not as big as the function call time. It can be seen that it is in exchange for time savings at the cost of the increase of the target code.