What is wrong with using inline functions?
Asked Answered
P

13

39

While it would be very convenient to use inline functions at some situations,

Are there any drawbacks with inline functions?

Conclusion:

Apparently, There is nothing wrong with using inline functions.

But it is worth noting the following points!

  • Overuse of inlining can actually make programs slower. Depending on a function's size, inlining it can cause the code size to increase or decrease. Inlining a very small accessor function will usually decrease code size while inlining a very large function can dramatically increase code size. On modern processors smaller code usually runs faster due to better use of the instruction cache. - Google Guidelines

  • The speed benefits of inline functions tend to diminish as the function grows in size. At some point the overhead of the function call becomes small compared to the execution of the function body, and the benefit is lost - Source

  • There are few situations where an inline function may not work:

    • For a function returning values; if a return statement exists.
    • For a function not returning any values; if a loop, switch or goto statement exists.
    • If a function is recursive. -Source
  • The __inline keyword causes a function to be inlined only if you specify the optimize option. If optimize is specified, whether or not __inline is honored depends on the setting of the inline optimizer option. By default, the inline option is in effect whenever the optimizer is run. If you specify optimize , you must also specify the noinline option if you want the __inline keyword to be ignored. -Source

Procurable answered 13/9, 2008 at 20:25 Comment(4)
Nice summary. Note that your bullets about when inline is applied by the compiler and when not are rather compiler specific. (MSVC will do that one differently from gcc differently from ...)Drama
"There are few situations where an inline function may not work: For a function returning values; if a return statement exists. For a function not returning any values" You can also just say "inline functions may never work".Justle
Your points concentrate only on performance. IMO the more important point is that inline allows to avoid ODR violations for standalone functions defined in header-only libraries. This is a use of inline that the compiler cannot ignore. It may still decide against actually inlining the function, but it must treat it as if there is only one definition.Nerynesbit
More explanation for the ODR thing.Nerynesbit
D
22

It worth pointing out that the inline keyword is actually just a hint to the compiler. The compiler may ignore the inline and simply generate code for the function someplace.

The main drawback to inline functions is that it can increase the size of your executable (depending on the number of instantiations). This can be a problem on some platforms (eg. embedded systems), especially if the function itself is recursive.

I'd also recommend making inline'd functions very small - The speed benefits of inline functions tend to diminish as the function grows in size. At some point the overhead of the function call becomes small compared to the execution of the function body, and the benefit is lost.

Dehydrate answered 13/9, 2008 at 20:38 Comment(0)
M
14

It could increase the size of the executable, and I don't think compilers will always actually make them inline even though you used the inline keyword. (Or is it the other way around, like what Vaibhav said?...)

I think it's usually OK if the function has only 1 or 2 statements.

Edit: Here's what the linux CodingStyle document says about it:

Chapter 15: The inline disease

There appears to be a common misperception that gcc has a magic "make me faster" speedup option called "inline". While the use of inlines can be appropriate (for example as a means of replacing macros, see Chapter 12), it very often is not. Abundant use of the inline keyword leads to a much bigger kernel, which in turn slows the system as a whole down, due to a bigger icache footprint for the CPU and simply because there is less memory available for the pagecache. Just think about it; a pagecache miss causes a disk seek, which easily takes 5 miliseconds. There are a LOT of cpu cycles that can go into these 5 miliseconds.

A reasonable rule of thumb is to not put inline at functions that have more than 3 lines of code in them. An exception to this rule are the cases where a parameter is known to be a compiletime constant, and as a result of this constantness you know the compiler will be able to optimize most of your function away at compile time. For a good example of this later case, see the kmalloc() inline function.

Often people argue that adding inline to functions that are static and used only once is always a win since there is no space tradeoff. While this is technically correct, gcc is capable of inlining these automatically without help, and the maintenance issue of removing the inline when a second user appears outweighs the potential value of the hint that tells gcc to do something it would have done anyway.

Mischiefmaker answered 13/9, 2008 at 20:28 Comment(5)
In VC++ it will increase the size, not sure about other compilers. But if they do chose to make it inline I'm sure it would make it larger too.Bose
by they I mean the compiler in question.Bose
Yes, the size increment was the major one i heard of.. curious to know if there are more!Procurable
Much more important than the length of the function, IMHO, is the question of whether knowledge of the arguments passed at various call sites will allow optimizations to be applied specifically to them. There are many situations where 99% of calls to a certain function will pass a constant [not always the same one] to a particular argment, and where knowledge that a certain parameter will be constant will allow the compiler to omit 90%+ of the code associated with a function.Bracknell
@BrianR.Bondy: Inlining tiny functions that get or set a single member will typically decrease the size of a binary. It takes more instructions to set up and make a call than it does to load or store one thing, and the possibility of optimization after inlining often means something can just be kept in a register throughout a loop instead of making repeated calls.Shout
S
6

There is a problem with inline - once you defined a function in a header file (which implies inline, either explicit or implicit by defining a body of a member function inside class) there is no simple way to change it without forcing your users to recompile (as opposed to relink). Often this causes problems, especially if the function in question is defined in a library and header is part of its interface.

Shirk answered 15/9, 2008 at 22:20 Comment(2)
Yes, this is an often missed issue with inline functions exported from a shared library!Italian
This can also be an advantage because your users don't have to link to a .lib file. Makes single-file header-only libraries possible, which are easy to distribute and use. It is nothing worse than template libraries, which are quite common.Nerynesbit
J
4

I agree with the other posts:

  • inline may be superfluous because the compiler will do it
  • inline may bloat your code

A third point is it may force you to expose implementation details in your headers, .e.g.,

class OtherObject;

class Object {
public:
    void someFunc(OtherObject& otherObj) {
        otherObj.doIt(); // Yikes requires OtherObj declaration!
    }
};

Without the inline a forward declaration of OtherObject was all you needed. With the inline your header needs the definition for OtherObject.

Jerid answered 13/9, 2008 at 22:28 Comment(1)
I don't believe in practice your first bullet is correct. The compiler is OK to ignore inline but it only has the option if the definition of the function is visible at the call site and that more or less limits you to functions local to the current TU.Extreme
D
4

As others have mentioned, the inline keyword is only a hint to the compiler. In actual fact, most modern compilers will completely ignore this hint. The compiler has its own heuristics to decide whether to inline a function, and quite frankly doesn't want your advice, thank you very much.

If you really, really want to make something inline, if you've actually profiled it and looked at the disassembly to ensure that overriding the compiler heuristic actually makes sense, then it is possible:

  • In VC++, use the __forceinline keyword
  • In GCC, use __attribute__((always_inline))

The inline keyword does have a second, valid purpose however - declaring functions in header files but not inside a class definition. The inline keyword is needed to tell the compiler not to generate multiple definitions of the function.

Demeanor answered 14/9, 2008 at 12:26 Comment(4)
You probably mean "defining" functions in header files rather than declaring.Extreme
The definition must be available in order for the compiler to decide if it will inline the function or not. Intra-TU this requires that the definitions be visible in the header file - which requires the 'inline' keyword. It therefore brings us back to the developer having to make the call.Extreme
"In actual fact, most modern compilers will completely ignore this hint." Can you back this up with sources? In the clang documentation, it is stated that it's treated as a hint, but certainly not completely ignored. MSVC documentation states something similar. Your statement does not hold for two of the most popular "modern" compilers.Furnary
@rdb: The hint itself is probably meaningless, but the inline keyword also promises that all other callers of the function will also be able to see the definition. Not having to also emit a stand-alone definition for a function may weigh in favour of inlining.Shout
B
2

I doubt it. Even the compiler automatically inlines some functions for optimization.

Benedicto answered 13/9, 2008 at 20:26 Comment(2)
I'd amplify what @Benedicto said, and declare that "inline" is the "register" of the 2000s. Remember the "register" keyword? Has anybody used it since the 1980s?Monda
@PaulTomblin: The C standard provides that multiple translation units may declared inline functions of the same name, and recommends that they be folded into a common definition; in most cases code which uses inline could be made to work on a compiler that doesn't recognize it via #define inline static, but use of inline on a compiler which does understand it would generally yield better results than static.Bracknell
K
2

I don't know if my answer's related to the question but:

Be very careful about inline virtual methods! Some buggy compilers (previous versions of Visual C++ for example) would generate inline code for virtual methods where the standard behaviour was to do nothing but go down the inheritance tree and call the appropriate method.

Klausenburg answered 16/9, 2008 at 7:35 Comment(0)
A
1

You should also note that the inline keyword is only a request. The compiler may choose not to inline it, likewise the compiler may choose to make a function inline that you did not define as inline if it thinks the speed/size tradeoff is worth it.

This decision is generaly made based on a number of things, such as the setting between optimise for speed(avoids the function call) and optimise for size (inlining can cause code bloat, so isn't great for large repeatedly used functions).

with the VC++ compiler you can overide this decision by using __forceinline

SO in general: Use inline if you really want to have a function in a header, but elsewhere theres little point because if your going to gain anything from it, a good compiler will be making it inline for you anyway.

Apfelstadt answered 13/9, 2008 at 20:41 Comment(0)
F
1

Inlining larger functions can make the program larger, resulting in more instruction cache misses and making it slower.

Deciding when a function is small enough that inlining will increase performance is quite tricky. Google's C++ Style Guide recommends only inlining functions of 10 lines or less.

(Simplified) Example:

Imagine a simple program that just calls function "X" 5 times.

If X is small and all calls are inlined: Potentially all instructions will be prefetched into the instruction cache with a single main memory access - great!

If X is large, let's say approaching the capacity of the instruction cache:
Inlining X will potentially result in fetching instructions from memory once for each inline instance of X.
If X isn't inlined, instructions may be fetched from memory on the first call to X, but could potentially remain in the cache for subsequent calls.

Foozle answered 14/9, 2008 at 11:58 Comment(2)
Can you elaborate on or provide an example (a usage pattern, perhaps) showing how a large inline function results in more cache misses? Suppose we only have one large inline function that is used frequently, wouldn't it actually reduce the number of cache misses by increasing locality of reference?Dishonorable
@nawK: Added an example. When a function is large enough, your locality of reference (for instructions) can get decrease with inlining, as each inlined instance is a separate copyFoozle
C
0

Excessive inlining of functions can increase size of compiled executable which can have negative impact on cache performance, but nowadays compiler decide about function inlining on their own (depending on many criterias) and ignore inline keyword.

Conferral answered 13/9, 2008 at 20:31 Comment(0)
O
0

Among other issues with inline functions, which I've seen heavily overused (I've seen inline functions of 500 lines), what you have to be aware of are:

  • build instability

    • Changing the source of an inline function causes all the users of the header to recompile
    • #includes leak into the client. This can be very nasty if you rework an inlined function and remove a no-longer used header which some client has relied on.
  • executable size

    • Every time an inline is inlined instead of a call instruction the compiler has to generate the whole code of the inline. This is OK if the code of the function is short (one or two lines), not so good if the function is long
    • Some functions can produce a lot more code than at first appears. I case in point is a 'trivial' destructor of a class that has a lot of non-pod member variables (or two or 3 member variables with rather messy destructors). A call has to be generated for each destructor.
  • execution time

    • this is very dependent on your CPU cache and shared libraries, but locality of reference is important. If the code you might be inlining happens to be held in cpu cache in one place, a number of clients can find the code an not suffer from a cache miss and the subsequent memory fetch (and worse, should it happen, a disk fetch). Sadly this is one of those cases where you really need to do performance analysis.

The coding standard where I work limit inline functions to simple setters/getters, and specifically say destructors should not be inline, unless you have performance measurements to show the inlining confers a noticeable advantage.

Oldham answered 25/7, 2016 at 8:34 Comment(0)
V
0

In addition to other great answers, at least once I saw a case where forced inlining actually slowed down the affected code by 1.5x. There was a nested loop inside (pretty small one) and when this function was compiled as a separate unit, compiler managed to efficiently unroll and optimize it. But when same function was inlined into much bigger outer function, compiler (MSVC 2017) failed to optimize this loop.

Viguerie answered 16/11, 2021 at 14:28 Comment(0)
M
-1
  1. As other people said that inline function can create a problem if the the code is large.As each instruction is stored in a specific memory location ,so overloading of inline function make a code to take more time to get exicuted.

  2. there are few other situations where inline may not work

    1. does not work in case of recursive function.
    2. It may also not work with static variable.
    3. it also not work in case there is use of a loop,switch etc.or we can say that with multiple statements.
    4. And the function main cannot work as inline function.
Manion answered 24/7, 2016 at 17:14 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.