tags:

views:

89

answers:

2

Possible Duplicate:
Two questions about inline functions in C++

Hi, Can i declare my function as "inline" if it is a recursive function? I've heard it may be a bit problematic/dangerous. I'd like to understand the reasons behind all this.

Thanks!

+3  A: 

You can declare it inline if you like, but it will do nothing because the function obviously cannot be inlined. Note that, in general, the compiler is free to completely ignore any and all inline requests.

That being said, it may actually get inlined if the compiler removes the recursion. A common technique used is the tail-call optimisation, which changes functions that call themselves recursively at the end of the function into iterative functions. For example:

int factorial(int n)
{
  if (n == 1) return 1;
  return n * factorial(n - 1);
}

would get transformed into:

int factorial(int n, int accum = 1)
{
start:
  if (n == 1) return accum;
  accum *= n;
  n = n - 1;
  goto start;
}

which could be inlined.

Note that while the compiler is free to not inline functions declared with inline, it cannot ignore your request for internal linkage i.e. you can still define your inline recursive function in a header file and include it with many cpp files without worrying about multiple definitions.

Peter Alexander
`inline` does not do nothing. It changes the "one definition" rules so that the function can be defined in multiple translation units. The compiler cannot ignore this aspect of `inline` whether or not it actually can or does perform inline expansion of function calls.
Charles Bailey
Ok, ok, Mr. Pedantic. Obviously I was referring to the fact that it won't actually inline the function, but I'll add that for completeness :)
Peter Alexander
c++ doesn't support tail recursion.
JoshD
I honestly don't think I'm being _too_ pedantic on this one. So many people misunderstand what `inline` hints and what it actually requires that it never hurts to be explicit and complete. ... IMHO
Charles Bailey
@JohnD: C++ doesn't prohibit tail recursion. So long as the effect of what the compiler does not deviate from what the standard requires, a compiler can perform what transformations and optimizations it deems fit.
Charles Bailey
@Charles: I see. I've been lied to!!! Are there any compilers that do this optimization that you're aware of?
JoshD
@JoshD: There's a question for that: http://stackoverflow.com/questions/34125/which-if-any-c-compilers-do-tail-recursion-optimization
Ben Voigt
gcc happily compiles this into a iterative solution at levels greater than `-O1`. `unsigned sum(unsigned x) { return x ? x + sum(x - 1) : 0; }`
Charles Bailey
`inline` functions have external linkage unless they're otherwise given internal linkage (e.g. by a previous declaration as a `static` function). `inline` doesn't give a function automatic internal linkage.
Charles Bailey
A: 

To understand the reasons why inlining doesn't make sense, you have to think about what inlining a function does.

When it's inline, it will essentially ask the compiler to replace the function call with the body of the function (the compiler can ignore this). So if you did this recursively, it'd be infinite. Let's look at an example:

int factorial(int n) {
  if (n == 0 || n == 1)
    return 1;
  return n * factorial(n-1);
}

Now, if this were inlined, we'd first replace a call to factorial with it's body. Looking at the body of factorial itself, we'd have to replace the call factorial(n-1). This gives:

int factorial(int n) {
  if (n == 0 || n == 1)
    return 1;
  return n * ((( if (n-1 == 0 || n-1 == 1)
    return 1;
  return (n-1) * factorial(n-1-1); )));
}

I'm using tripple parenthesis to indicate code replacement. Of course this isn't exactly valid code, but it ilustrates my point.

From here, we have another factorial call inside the new code, so we replace that, and on ad infinitum.

So, that's reasoning behind why such a thing isn't done. Modern compilers are clever enough not to do this for exactly this reason, though.

JoshD
It would be a poor compiler that went into an infinite loop because of a legal use of `inline`. `inline` never requires inline expansion of function calls and clearly a compiler should attempt it if it's going to cause a compilation failure.
Charles Bailey
this will not cause the compiler to be in an infinite loop. compiler will just ignore it.
Donotalo
Yes. I noted that the compiler can choose not to inline. I'm trying to explain why a recursive function wouldn't be inlined as the question asked (if I understood the question.)
JoshD
typo: obviously I meant: "...should **not** attempt..."
Charles Bailey
@JoshD, that's not what you've written though - "You'll cause an infinite loop in the compiler" - that seems to very definitively say that declaring a recursive function `inline` will cause an infinite loop, which, if true in your case, means you need to switch to another compiler!
Praetorian
@Praetorian: I see that would be misleading (I meant it hypothetically along with the hypothetical example, but I see that it isn't clear the way I wrote it). I've changed it. Thanks for pointing it out.
JoshD