23

According to what I read, the compiler is not obliged to substitute the function call of an inline function with its body, but will do so if it can. This got me thinking- why do we have the inline word if that is the case? Why not make all function inline functions by default and let the compiler figure out if it can substitute the calls with the function body or not?

1

7 Answers 7

46

inline is from C; it was not new to C++.

There are C keywords (register and inline) that were designed to allow the programmer to assist in code optimization. These are generally ignored nowadays, since compilers can do better at register assignment and deciding when to inline functions (in fact, a compiler can either inline or not inline a function at different times). Code generation on modern processors is far more complicated than on the more deterministic ones common when Ritchie was inventing C.

What the word means now, in C++, is that it can have multiple identical definitions, and needs to be defined in every translation unit that uses it. (In other words, you need to make sure it can be inlined.) You can have an inline function in a header with no problems, and member functions defined in a class definition are automatically effectively inline.

5
  • 4
    +1 for the history of inline. Commented Jan 10, 2011 at 18:53
  • 13
    I'm pretty sure that inline was standardized in C++ first, although it was already available as a vendor extension in C.... yep, seems it was added to the C standard in C99.
    – Ben Voigt
    Commented Jan 10, 2011 at 22:30
  • @Ben Voigt: You're right. I first encountered it in C. Commented Jan 11, 2011 at 15:16
  • 7
    Also be aware that not only is the history wrong, but the rules for inline in C99 and later are different from the rules for inline in C++. Commented Aug 20, 2014 at 22:52
  • Any proof compilers ignore it?
    – None
    Commented Oct 21, 2020 at 12:14
27

Originally inline was a very strong hint that calls to the function should be inlined.

But the only guaranteed effect of inline is to allow a function to be defined (effectively identically) in multiple translation units, e.g., that you place the definition in a header file.

Nowadays, some compilers are very keen on following the inlining hint, e.g. g++. And some compilers take it less seriously, e.g. Visual C++. But all have to abide by the guarantee.

It is unfortunate that these two meanings -- optimization hint and what we might call a linker level discardable definition -- reside with the same keyword, because it means that you cannot practically have one without the other.

It is also unfortunate that inline (or better, a separate keyword about discardable definition) ¹cannot be applied to data.

The need for linker level discardable data has increased as header-only modules have become more popular. E.g., many Boost sub-libraries are header-only.

For data you can, however, apply a little trick with templates. Define it in some class template, provide a typedef with template parameter void (or whatever). That's because the One Definition Rule makes a specific exception for templates.

Notes:
¹ inline variables will be supported in C++17.

2
  • 1
    +1 for the extra information about inline. Commented Jan 10, 2011 at 18:53
  • 2
    "effectively identically" is actually a very tricky condition, as the very badly designed C++ languages tries very hard to make normally competent and careful programmers write reasonable but formally undefined code that uses static objects - I wonder how many committee members fall into the trap themselves
    – curiousguy
    Commented Nov 8, 2018 at 0:02
6

Why not make all functions inline by default? Because it's an engineering trade off. There are at least two types of "optimization": speeding up the program and reducing the size (memory footprint) of the program. Inlining generally speeds things up. It gets rid of the function call overhead, avoiding pushing then pulling parameters from the stack. However, it also makes the memory footprint of the program bigger, because every function call must now be replaced with the full code of the function. To make things even more complicated, remember that the CPU stores frequently used chunks of memory in a cache on the CPU for ultra-rapid access. If you make the program's memory image big enough, your program won't be able to use the cache efficiently, and in the worst case inlining could actually slow your program down. To some extent the compiler can calculate what the trade offs are, and may be able to make better decisions than you can, just looking at the source code.

2
  • 5
    But the compiler can (and does!) figure this out much better than the programmer in general. So this is not a valid argument. Commented Jan 10, 2011 at 20:36
  • "every function call must now be replaced with the full code of the function" And inline function isn't a function where the call sequence is omitted and where the assembly code of the function is copied in place. An inline function is compiled in place, by bringing the high level intermediate code inline. That allows the compiler to treat the function body effectively as a clean macro (a clean macro is one that doesn't have the quirks of C preprocessor macros), with potentially many optimizations available.
    – curiousguy
    Commented Nov 8, 2018 at 0:05
3

To understand “inline” you need to understand history and what life was like 20 (and 30) years ago.

We were writing code on computers that had little memory, so it was not possible for a compiler to process all the code that made up a program on one go. Compiler was also very slow, so you did not want to have to recompile code that had not changed – taking over 24hr (on a computer that cost as more than a top end car) to recompile all the code was normal for a few projects I worked on.

Therefore each code file was separately compiled into an object files. Each object file started with list of all function it contained, along with the “address” of the function. An object file also had a list of all functions it called in other object files along with the location of the call.

A linker would first read all the object files, and build up a list of all functions they exported, along with the file they were in and there address. It would then reread all the object files, outputting them to the programme file, while updating all “external” function calls with the address of the function.

The linker did not change or optimise the machine code produced by the compiler in any way other than to fix up references to external function calls. The linker was part of the operating system and predates most compilers. When people wrote a new compiler they needed it to work with current linkers, and to be able to link to current object files, otherwise system calls could not be made.

The compiler only ever saw the code in the “.c” or “.cpp” file it was compiling along with all included header files. So it could not make any optimisation based on code in other “.c” or “.cpp” files.

The “inline” keyword allowed the body of a function (method) to be defined in a header file, hence allowing the compiler to make use of the code of the function while compiling code that calls it. For example say you had a collection class defined in anther .cpp file, this class would have an “isEmpty” method, that contained one line of code, there would be a big speedup of the resulting program if instead of a call to a function, the function call was replaced with this one line.

The “inline” keyword was seen at the time as a “cheap and easy” way to allow encapsulation of data while avoiding the cost of function calls, without it a lot of programmers would have just access the private fields of the object. (Macros where a much worse way “inlining” code that where common at the time.)

These days “linkers” do a lot of code optimisation and tend to be written by the some team as the compiler. The compiler often just checks the code is correct and “compresses” it, leaving most of the task of machine code creation to the linker.

2

Let's see what the standard says (highlighted important parts in bold):

2. A function declaration with an inline specifier declares an inline function. The inline specifier indicates to the implementation that inline substitution of the function body at the point of call is to be preferred to the usual function call mechanism. An implementation is not required to perform this inline substitution at the point of call; however, even if this inline substitution is omitted, the other rules for inline functions shall still be respected.

C++ standard, ISO/IEC 14882:2003, 7.1.2 Function Specifiers [dcl.fct.spec]

So, if you want to be sure, you should read the documentation of your compiler.

Inlining everything is a bad idea, as it might result in a lot of duplicated machine code...

So you'll have to know:

There are no simple answers: You have to play with it to see what is best. Do not settle for simplistic answers like, "Never use inline functions" or "Always use inline functions" or "Use inline functions if and only if the function is less than N lines of code." These one-size-fits-all rules may be easy to write down, but they will produce sub-optimal results.

C++ FAQ, Inline Functions, 9.3 Do inline functions improve performance?

5
  • 1
    What you say is true, but not relevant because as the programmer it's not your decision whether to inline or not. You put the keyword, you might or might not get your functions inlined. You don't put the keyword, you still might or might not get them inlined. It's pointless to have ANY rules for when you put the keyword, what with the compiler being the one actually making the decision. Commented Jan 19, 2011 at 15:05
  • How isn't this relevant if it says exactly the same as you? There are no simple answers. Commented Jan 19, 2011 at 15:10
  • It's not relevant because it doesn't answer the OPs question. He's not asking "what does inline do", he's asking "whats the point". And your answer just reiterates what we all already know about inline. Commented Jun 11, 2011 at 19:46
  • @Davor: "What's the point?" doesn't adhere to the FAQ, so I'm answering the questions posed within the question. I'm telling the point of inline by reiterating the knowledge as the OP seems to miss a part so which is the core reason why he doesn't get the point. For one to get a point he needs to have an understanding of what's beneath that point... Commented Jun 11, 2011 at 19:50
  • Why the hell wouldn't it adhere to the FAQ? Standard describes syntax and semantics of inline keyword, and OPs question is what is the purpose, when should it be used, what problems is it supposed to solve? I don't see how that doesn't adhere to the FAQ. Commented Jun 11, 2011 at 22:00
1

Let me give you a good reason for using the inline keyword.

On an embedded system, such as an ticket printer or similar smaller system. The processor is very limited and a function call (preparing function parameters on stack, call, fetch params from stack and put back answer etc..) can take several ms to execute, beside the function itself.

Lets say the call time is about 60ms (just for calling, not the actual function) and you have do 50 iterations (loop or iterative calls in a tree).

The time to just move forth and back from that function call will take 60 * 50 = 3000 (3 seconds).

If you have the memory you would definitely do an inline to save 3 seconds.

So inline are basically used when you need execution speed. In some projects I was involved with, the calling time was longer than the execution time, a classic situation when to use inline.

2
  • Eh, what? Putting inline in your code doesn't mean that compiler will actually inline it, and not putting it there also doesn't mean that it wont. It's just a hint, which is mostly ignored by todays compilers. If compiler finds it useful to inline, then it will, otherwise, it wont. You have no real control there. OP already knows this, and is asking, i quote: "What's the point?". Who the hell gives +1 on this? It's both misleading (implying that keyword inline enforces inlining) and irrelevant to the question. Commented Jun 11, 2011 at 19:52
  • 3
    @Davor Ždralo No need to be rude. I interpreted the question as WHY should I use inlines? My point was to show that you can get the code faster at cost of memory. Each compiler may handle the inline keyword different, so you need to check the documentation, which I didn't mention. Since you can't always afford the extra memory overhead inlines creates, it is useful to "guide" when to use it. I also didn't say that inlines are enforced. Someone found this answer useful to him/her and voted +1, please respect that other may have another level of experience and find something trivial useful. Commented Jun 13, 2011 at 18:15
1

As others have already said, the implementation (i.e. compiler) gets to decide if and when a given function call gets is inlined or not. Most compilers let users can tune that through the compiler flags. For example, with GCC:

-fno-inline

Do not expand any functions inline apart from those marked with the always_inline attribute. This is the default when not optimizing.

So, when you call GCC with the -O0 flag, it won't inline.

GCC and LLVM both support the the always_inline attribute, which (respectively):

Generally, functions are not inlined unless optimization is specified. For functions declared inline, this attribute inlines the function even if no optimization level is specified.

Inlining heuristics are disabled and inlining is always attempted regardless of optimization level.

For those wanting a more in-depth look at function inlining, these are some interesting resources that I found:

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.