Previous      Up      Previous     Course Home   e-mail

2.17 What is an inline function?

When we define a function, it is usually compiled into a self-contained unit of code. For example, a function


int foo ( int a , int b )
{
return a + b - 1;
}
would compile into a block of code equivalent to
stack[1] = stack[3] + stack[2] - 1;
jump to address in stack[0]
where the “stack” is the runtime stack a.k.a. the activation stack used to track function calls at the system level, stack[0] is the top value on the stack, stack[1] the value just under that one, and so on. A function call like

x = foo ( y , z +1);
would be compiled into a code sequence along the lines of
push y onto the runtime stack;
evaluate z+1;
push the result onto the runtime stack
push (space for the return value) onto the runtime stack
save all CPU registers
push address RET onto the runtime stack
jump to start of foo's body
RET: x = stack[1]
pop runtime stack 4 times
restore all CPU registers
As you can see, there’s a fair amount of overhead involved in passing parameters and return address information to a function when making a call. The amount of time spent on this overhead is really all that large. If the function body contains several statements of any kind of loop, then the overhead is probably a negligable fraction of the total time spent on the call.

class Foo {
private :
int bar ;
public :
int getBar ();
void setBar ( int );
};

int Foo :: getBar () { return bar ;}

void Foo :: setBar ( int b ) { bar = b ;}
But many ADTs have member functions that are only one or two lines long, and often trivial lines at that. For these functions, the overhead associated with each call may exceed the time required to do the function body itself. Furthermore, because these functions are often the primary means of accessing the ADT’s contents, sometimes these functions get called thousands of times or more inside the application’s loops.

For these kinds of trivial functions, C++ offers the option of declaring them as inline.

class Foo {
private:
   int bar;
public:
   int getBar () {return bar;}
   void setBar (int);
};

inline
void Foo::setBar (int b) {bar = b;}

An inline function can be written one of two ways. First, it can be written inside the class declaration. Second, we can place the reserved word inline in front of the function definition written in its usual place outside the class declaration. When we make a call to an inline function, the compiler simply replaces the call by a compiled copy of the function body (with some appropriate renaming of variables to avoid conflicts). So, if we have


inline int foo ( int a , int b )
{
return a + b - 1;
}
and we later make a call

x = foo ( y , z +1);
This would be compiled into a code sequence along the lines of
evaluate z+1, storing result in tempB
evaluate y + tempB - 1, storing result in x
Most of the overhead of making a function call hs been eliminated.

Inline functions can reduce the run time of a program by removing unnecessary function calls, but, used unwisely, may also cause the size of the program to explode. Consequently, they should be used only by frequently-called functions with bodies that take only 1 or 2 lines of code. For larger functions, the times savings would be negligable (as a fraction of the total time) while the memory penalty is more severe, and for infrequently used functions, who cares?

Inlining is only a recommendation from the programmer to the compiler. The compiler may ignore an inline declaration and continue treating it as a conventional function if it prefers. In particular, note that inlining of functions with recursive calls is impossible, as is inlining of most virtual function calls. Many compilers will refuse to inline any function whose body contains a loop. Others may have their own peculiar limitations.

 Previous      Up      Previous     Course Home   e-mail