tags:

views:

136

answers:

5

If I define a non-member function in a header, will it always be inlined by the compiler, or does the compiler choose based on its heuristics? I know that __inline is just a hint, is it the same with functions in headers?

+2  A: 

It will choose based on heuristics. Make sure you declare it as inline explicitly otherwise you may get a duplicate symbol link error if you include the header in more than one compilation unit.

Laserallan
+11  A: 

Remember that including something from a header is no different than just typing it directly in the source file. So being in a header makes no difference as far as the compiler is concerned; it never knew it was there.

So when you define a function in a header file, and you include that header file in a file, it's like you just typed the function straight into the file. So now the question is, "does the compiler choose to inline things based on heuristics?"

The answer is "it depends on the compiler". The standard makes no guarantees about what gets inlined or not. That said, any modern compiler will be extremely intelligent about what it inlines, likely with heuristics.

However, we come to an interesting point. Imagine you have a function in a header and you include that header in multiple source files. You will then have multiple definitions of the function, across translation units, and this violates the one-definition rule. Ergo, you will get compile errors. (The linker error is usually something along the lines of: "Error, function x already defined in y") What you can do is use the inline keyword and you no longer violate the ODR.

By the way __inline is non-standard. Contrary to your post, it's usually a compiler extension which forces inlining, not hints it. inline is the standard keyword, which was originally intended to hint at inlining. Like you say, most modern compilers completely ignore it in that regard and it's only purpose nowadays is to give things internal linkage.

GMan
Any thoughts on what heuristics a modern compiler like g++ uses in its decision? i.e. is it along the lines of "inline any function that where the ratio of call sites to bytes-in-function-body is less than X"? Or is it something more subtle?
Jeremy Friesner
@Jeremy: I have no idea, though I'm pretty interested now that you mention. I'll be able to look tonight. I suspect it's quite complicated.
GMan
@GMan: The bit about internal linkage is incorrect. `inline` has no effect on linkage. In C++ a function declared `inline` has external linkage (unless specifically declared `static`), just like any other function. The ODR for inline functions specifically allows multiple definitions in different translation units, even though the linkage is external.
AndreyT
In other words, `inline` is that pecular keyword that allows one to work around ODR, while keeping the *external* linkage of the function. Otherwise, it wouldn't be any different from `static`.
AndreyT
Indeed, that it still has external linkage is a *key* feature of `inline`. Since local statics are associated with their function (different from C), `inline int id() { static int i = ios_base::xalloc(); return i; }` will return the same integer no matter from what TU it's called, and can appear in headers. Having still external linkage and therefor the same address in all TUs, it can also be used as template arguments to non-type parameters.
Johannes Schaub - litb
Fixored, I'm dumb.
GMan
+4  A: 

From the C++ FAQ Lite:

No matter how you designate a function as inline, it is a request that the compiler is allowed to ignore: it might inline-expand some, all, or none of the calls to an inline function.

mwigdahl
+2  A: 

If you define a function with external linkage in a header file and include it into more than one translation unit, you'll get compilation error (more precisely: linker erorr) for violation of One Definition Rule (ODR). So the answer is "no": defining a function in a header file will not be taken by compiler as a hint at inlining and will not excuse you from observing the requirements of ODR. Not only such functions are not guaranteed to be inlined, but most likely your program will not even compile.

In order to define a function in a header file and get away with it you have to either give it internal linkage (declare it static, and end up with separate function in each translation unit), or explicitly declare it inline.

As for the heuristics... Modern compilers will normally consider virtually any function for inlining (by applying heuristics), regardless of where it is defined and whether it is explicitly declared inline or not.

AndreyT
+1  A: 

There is no magic about functions in headers. The compiler doesn't even know whether a function is defined in a header or not. (Since headers are effectively just copy/pasted into the source file, you might define it in a header, but the compiler just sees it as part of the translation unit)

There are also two different meanings of "inline" to be aware :

A function may be inlined as defined by the C++ standard: This is done either by prefixing the function with the inline keyword, or if it is a member function, by defining it in-place inside the class definition.

The effect of this is to

  • inform the linker that it may encounter the function definition in multiple files, and it should just silently merge them together instead of throwing an error
  • make it easier for the compiler to perform the inlining optimization.

The inlining optimization on the other hand, is simply the act of replacing a function call by the body of the called function, which means that this optimization is actually applied to call sites, not to functions. A function might be called normally some places, but inlined elsewhere. A function call is inlined when the compiler feels like it, and it is best to conceptually separate it entirely from the first meaning of "inline".

The compiler will apply the inlining optimization if, when and where it feels like it. It uses a lot of heuristics for this. Smaller functions are more likely to be inlined. If it determines that a specific call site is going to be executed sufficiently often, it is more likely to be inlined. Ultimately, the heuristics it uses are based on "will it improve or degrade performance". And it is generally a better judge of this than human beings, so you shouldn't really need to know what precise heuristics it uses. Inlining too much will only harm performance.

jalf