Lesson 5 | Inlining |
Objective | Explore how inline functions can speed up programs. |
C++ Inline Functions
In an earlier lesson, you learned about the keyword inline
, which is a request to the compiler that the function be compiled without function call overhead.
The compiler may ignore this suggestion, but either way the semantics of the compiled functions are identical.
Use inline
in place of using the preprocessor define
directive that you're familiar with in C programming.
Why use inline?
Using the preprocessor to define macros has a clear drawback: the preprocessor does not understand C syntax. For example:
#define SQ(X) X * X
expands the code
SQ(a + b)
to
a + b * a + b
Since the * operator has higher precedence then +, the compiler would interpret this as
a + (b * a) + b
when what we really meant was
(a + b) * (a + b)
This problem can be avoided by fully parenthesizing the original macro. However, the solution does not protect against improper types being used. This latter defect is remedied by using inline
:
inline int SQ(int x) { return (x * x); }
Because the keyword inline requests that the compiler compile the function without function call overhead, you should only use inline for very short functions, for which function overhead is an issue.
Inline Functions
When function bodies are very short, such as with the comparison operators in class Fraction, the execution time involved in the function call (pushing arguments on to the activation record stack, transfer of control, return from function, popping arguments off the
stack) can often be greater than the execution time required by the body of the function itself. Moreover, many processors fetch and decode subsequent instructions as they execute an instruction. Branches and function calls slow down this mechanism.
When an inline function is invoked, the compiler expands the body of the function in place. This eliminates the execution cost of the function call, but results in multiple copies of the function body (one each time the function is called).
For this reason, inline functions should only be used when the function body is very short. To create an inline function the keyword inline is placed before the function body.
The function definition is then placed in the interface file, not the implementation file:
inline bool operator<(const Fraction& left, const Fraction& right){
return left.compare(right) < 0;
}
Member functions can also be inlined using a similar syntax:
inline Fraction& Fraction::operator++(){
top += bottom;
return *this;
}
It is also possible to place the body of an inlined member function directly into a class declaration. In this case the inline keyword is not necessary:
class Fraction{
//...
Fraction& Fraction::operator++(){
top += bottom;
return *this;
}
//...
};
However, this style can make reading the class definition difficult, since it combines interface and implementation features. In this book we will use only the first style.
A good rule of thumb is to use inlining when a function is three or fewer assignment statements, a single conditional (if) statement, and/or a return statement. Anything more complex should be written as a normal function.