Basically, when a function is called in assembly language (which is what your C++ code gets turned into by the compiler) it actually takes real time to set up the function and return from it. In pseudocode this is what a function actually is (C++ hides this from you):

  1. Save all temporary variables that you use (Assembly has a finite number of temporary registers, if you want to use one you have to save its state)
  2. Load the arguments of the function into some of those temporary variables.
  3. Use those variables somehow.
  4. Save the result in a special temporary variable (or to memory)
  5. Load all the same registers again.
  6. Return from the program.

So you can imagine that this:

int add(int a, int b)
{
    return a+b;
}
//...
int c;
c=add(1,2);

Becomes something more like this in assembly (obviously the code shown is not a real assembly language):

add://its a label, thats what assembly uses a lot of, please don't use them often in C++
    //this 'function' assumes that r0 (one of the temp registers) contains a
    //  and that r1 (another register) contains b already!
    push r2 //if we want to use r2 (yet another register) we need to save its state on the stack
    r2=r0+r1 //or more likely add r2,r0,r1, but the point is to store the value in r2
    //now lets assume we 'return' the value by storing it back into r0
    r0=r2
    pop r2 //reset the value of the register we used
    return //go back to where we called the code
//...
r0=1
r1=2
goto add //calls add, so r0+r1 is in r0
cout<<r0 //prints 3

The point is that you can see the overhead where the registers are saved to the call stack and usually 'return' actually involves somehow calculating where to goto to get back to code (using stack/frame pointers). Of course it would be much faster for the part after the ... to be more like:

r0=1
r1=2
r0=r0+r1

thats exactly what inline functions do. Instead of saving all the information about all of your variables, it instead copies in the 'source code' of the function directly to where you call it, so no function call ever actually happens.

Of course the compiler doesn't actually have to listen to you, if the function is too hard to in-line then the compiler just won't do it.

You can think of in-line functions like Macros with typechecking. It does a sort of copy-paste in your code, but only after it checks to make sure that your code satisfies the type conditions.

Hope this helps.

Actually, usually the temporary variables, arguments, call and return points are pushed onto the stack, for normal function calls. Inline code just gets converted into code as though you typed it directly into the translation unit (as you indicated toward the end of the post). As you indirectly pointed out, if the inline function is too complex, then the compiler is free to turn it into a local static function, and call it via normal means. Local variables are still pushed onto the stack. Some optimizations may use registers, but not by default, as far as I am aware. Of course, you can specify that a function argument or variable is a "register" type, but the compiler is free to ignore that if there are no free registers to use. Caveat Programmer - you cannot take the address of a register variable or argument!

FWIW, C++ class methods that are implemented in the header are "inline" by default, even without the inline directive. This is why one wants to only implement simple getter/setter or other methods in the header. More complex methods should be implemented in the source file, out-of-line. People who come to C++ from Java often don't realize that implementing all the code in the header is not necessarily a "good thing", and can cause serious code bloat. Why? Because everything in Java is effectively "inline". It is all implemented in the class definition. C++ is another thing entirely! :-)

Anyway, I think that generally your post was a good one Labdabeta. Keep it up!

This article has been dead for over six months. Start a new discussion instead.