What is the difference between an
ordinary function and a static
function "in terms of memory
allocation only" ?
Nothing. A static function is just like a global function except for the scope.
Even for non-static member functions, there's no extra memory required. The member function int C::f(int arg1, int arg2)
is just syntactic sugar for something like int C__f(C* this, int arg1, int arg2)
.
What if the member function contains
some local variables ? In that case
the function "should" have a separate
copy of that variable - specific to
the object invoking the function...
There's a copy of the local variables for each invocation of the function (unless they're static
). This is why recursion in possible in C++.
How is this problem solved in C++ ?
Function calls are based around "stack frames". A stack frame consists of:
- The arguments to the function (including the implicit
this
if applicable).
- Any other non-
static
local variables in the function.
- The "return address", which tells the processor where to resume execution once the function is done.
Whenever a function is called, a stack frame is created. When the function is, the stack frame is destroyed. If a function is called recursively, each level of recursion gets its own stack frame. For example, if you have
int factorial(int n) {
if (n <= 1)
return 1;
else
return factorial(n - 1) * n;
}
Then when you call factorial(3)
, a stack frame gets created like so:
------------------------ stack pointer (SP)
n = 3
RA = <in main()>
When the recursive call is made to factorial(2)
, an additional frame is added to the top of the stack
------------------------ SP
n = 2
RA = <in factorial()>
------------------------
n = 3
RA = <in main()>
Another recursive call is made, to factorial(1)
.
------------------------ SP
n = 1
RA = <in factorial()>
------------------------
n = 2
RA = <in factorial()>
------------------------
n = 3
RA = <in main()>
This is the base case for the recursion, and the return value of 1 is stored in a register. The function call being complete, the top stack frame is destroyed, and execution continues at saved return address.
------------------------ SP
n = 2
RA = <in factorial()>
------------------------
n = 3
RA = <in main()>
Now, the call to factorial(2)
can compute its return value (2), and another stack frame can be destroyed:
------------------------ SP
n = 3
RA = <in main()>
Finally, we can compute the result of the original function call (6), and destroy this stack frame too.