1: Definition:
They look like functions and operate like functions, which are much better than macro functions and do not need to bear the overhead of function calling. When a function is inline, the compiler can optimize the function body in a specific environment. Such optimization is impossible for "normal" function calls.
2: rules:
The Inline keyword must beFunction body DefinitionInline can be implemented only when the inline is put together before the function declaration. Inline is a keyword for implementation rather than a keyword for declaration. For Class methods, the methods defined inside the class body are automatically inline methods.
3: Implementation ideas:
The basic idea of inline functions is to replace each function call with its code body, it is very likely that the size of the entire target code will be increased. Excessive use of the program produced by the inner link will lead to insufficient space available because of the large size. Even if you can use virtual memory, the Code expansion caused by inline may lead to unreasonable page Scheduling (system bumps), which will make your program run as slowly as crawling, too many inline operations will also reduce the hit rate of instruction cache, thus reducing the speed of instruction fetch, because the master-slave access command is certainly slower than the slave cache. On the other hand, if the inline function body is very short, the code generated by the compiler for this function body will be much smaller than the code generated for the function call. In this case, the inline function will indeed bring a smaller target code and a higher cache hit rate!
The Inline command is like register. It is just a prompt to the compiler, not a command. That is to say, as long as the compiler is willing, it can ignore your instructions at will. In fact, the compiler often does this. For example, most compilers reject inline "complex" functions (such as cyclic and recursive functions); and, even the simplest virtual function call, the compiler's inline handler cannot help it. (This is not surprising. Virtual means "Wait until the runtime to decide which function to call", inline means "Replace the called place with the called function during compilation ", if the compiler does not even know which function will be called, it cannot be blamed for rejecting inline calls ).
4: Problems and Corresponding Solutions
Assume that a function f is written and declared as inline. If the compiler decides not to inline it for any reason, what will happen? The most obvious answer is to treat F as a non-inline function: when generating code for F, just like it is a common "external" function, the call to F is also like the call to a common function.
In theory, this should happen, but the theory and reality often deviate. This is the case now. This solution is ideal for solving the problem of "outlined inline", but it takes a relatively late time to add it to the C ++ standard. The earlier C ++ specification tells the compiler manufacturer to implement another different behavior, and this old behavior is still common in the current compiler, so you must understand what it is.
The above can be attributed to: whether a given inline function is actually inline depends on the specific implementation of the compiler used. Fortunately, most compilers can set the diagnostic level. When a function declared as inline is not actually inline, the compiler will issue a warning message for you.
Inline functions are actually defined in header files. This allows multiple units (source files) to be compiled to contain the same header file and share the benefits of inline functions defined in the header file.
// File example. h
Inline void F () {...} // F Definition
...
// File source1.cpp
# Include "example. H" // contains the definition of F
... // Contains the call to F
// File source2.cpp
# Include "example. H" // also contains the definition of F
... // ALSO CALLS F
Problem:
Assuming that the old "inline by external" rule is used and F is not inline, the generated target file will contain a function called F when source1.cpp is compiled, just as F is not declared as inline.
Similarly, when source2.cpp is compiled, the generated target file will also contain a function called F. When you want to link two target files together, the compiler will report an error because there are two F definitions in the program. In the. OBJ files generated by compilation of two CPP files, there is "inline by external" method F.
To prevent this problem,
Old rules:
For inline functions that are not inline, the compiler treats them as static, which limits them to the files currently compiled.
As shown in the preceding example, when the compiler that follows the old rule processes F in source1.cpp, it is like F is static in source1.cpp; when processing F in source2.cpp, it is also treated as static in source2.cpp.
This policy eliminates Link errors, but brings about overhead: Each compiled unit containing the definition of F (and calling f) contains its own static copy of F.
If f defines a local static variable, each copy of F will have a copy of this local variable, which will surprise programmers, because in general, the "static" in the function means "only one copy ".
New rule:
Using F as a non-inline function: when generating code for F, it is like a common "external" function, the call to F is also like the call to a common function.
Regardless of the new rule or old rule, if the inline function is not inline, each place where the inline function is called must bear the overhead of the function call; if it is an old rule, it must endure the increase in the size of the Code, because each compiled unit that contains (or calls) F has a copy of the Code of F and its static variables! (Worse, copying each F and copying each F's static variables are usually on different virtual memory pages, therefore, calling different copies of F may cause multiple page errors .)
More questions:
Sometimes, even if you really want to inline a function, the compiler has to generate a function body for this inline function. In particular, if the program needs to obtain the address of an inline function, the compiler must generate a function body for this. How can the compiler generate a pointer to a non-existent function?
Inline void F () {...} // same as above
Void (* PF) () = F; // pf points to F
Int main (){
F (); // inline call to F
PF (); // non-inline call to F through pf
...
}
This situation seems ridiculous: F calls are inline,
Old rules:
Each compilation unit that obtains the f address still generates a static copy of the function.
Under the new rule:
No matter how many units are involved, only one external copy of F will be generated.
Even if you never use function pointers, this kind of "inline functions that are not inline" will find your door, because not only programmers use function pointers, but sometimes compilers do the same. In particular, the compiler sometimes generates external copies of constructor and destructor, so that you can easily construct and analyze the object arrays of the class by getting the pointers of those functions.
In fact, a test can proveConstructor and destructor are often not suitable for inlineEven worse than the test results. For example, see the following constructor of this class derived:
Class base {
Public:
...
PRIVATE:
String bm1, bm2; // base class member
};
Class derived: public base {
Public:
Derived () {} // The derived constructor is empty, but is it true?
PRIVATE:
String DM1, dm2, dm3; // Member of the derived class-3
};
This constructor looks like a good inline material because it has no code. But appearance often deceives people! Because it does not have code, it does not mean that it really does not contain code. In fact, it contains a lot of code.
C ++ provides multiple rules on the events that occur when objects are created and destroyed. When new is used, dynamically created objects are automatically initialized by their constructor, and how the Destructor is called when Delete is used. When an object is created, each base class of the object and each data member of the object are automatically created. When the object is destroyed, the opposite process (that is, the analysis structure) is automatically executed ).
C ++ specifies what must happen, but does not specify "how" to happen. "How to happen" depends on the implementer of the compiler, but it should be clear that these events did not happen by themselves. There must be some code in the program to make them happen, especially the code written by the compiler implementers and inserted into your program during compilation. Sometimes they are hidden in your constructor and destructor.
Therefore, for the derived constructor called null above, some compilers will generate the following code for it:
// Possible implementation of a derived Constructor
Derived: erived (){
// Allocate heap memory to an object created on the stack;
If (the object is on the stack)
This =: perator new (sizeof (derived ));
Base: Base (); // initialize the base part.
Dm1.string (); // construct DM1
Dm2.string (); // construct DM2
Dm3.string (); // construct dm3
}
The code that calls operator new (if needed), the code that constructs the base class, and the code that constructs data members will be unknowingly added to your constructor, this increases the size of the constructor so that the constructor is no longer suitable for inline operations. Of course, the same analysis applies to the base constructor. If the base constructor is inline, all the code added to it will also be added to the derived Constructor (the derived constructor will call the base constructor ). If the string constructor happens to be inline, the derived constructor will get five copies of its code, each copy corresponds to one of the five strings in the derived object (Two Inherited and three declared ). Now you should understand that the constructor of inline derived is not easy to decide! Of course, similar situations also apply to the derived destructor. In any case, you must be clear that all objects initialized by the derived constructor will be completely destroyed. Previously, the destroyed object may occupy the dynamically allocated memory, so the memory needs to be released.
5. Rules for using inline functions
The library designer must estimate the declaration in advanceNegative impact of inline functions: it is impossible to upgrade the binary code of inline functions in the library.. In other words, if F is an inline function in the library, you will compile F's function body into your own program. If the library designer wants to modify F later, all user programs that use F must be re-compiled. On the contrary, if F is a non-inline function, you only need to relink the modification to F, which greatly reduces the workload compared to re-compilation; if the library containing this function is dynamically linked, the modification of the library is completely transparent to users.
Static objects in inline functions often violate intuition. Therefore, ifContains static objects. Avoid declaring it as an inline function..
In general, in actual programming, the original principle is not to inline any function, unless the function is really small and simple, as shown in the following age function:
class Person {
public:
int age() const { return personAge; }
...
private:
int personAge;
...
};
Careful use of inline not only gives the debugger more opportunities to play its role, but also positions the role of inline in the correct position: it is an optimization tool used as needed. Don't forget what you get from countless experiences. A program usually spends 80% of its time executing 20% of the Code. This is a very important law, because it reminds you that, as a programmer, a very important goal is to find out the code that can truly improve the performance of the entire program. You can choose to inline your function, or do not need to inline it, but these options only make sense on the "correct" function. Once the important functions in the program are identified, and those functions that can improve program performance after being inline (these functions depend on the system architecture of the system ), we will not hesitate to declare it as inline. At the same time, pay attention to the problems caused by code expansion to see if any inline function is not inline by the compiler.