Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why should I ever use inline code?

I'm a C/C++ developer, and here are a couple of questions that always baffled me.

  • Is there a big difference between "regular" code and inline code?
  • Which is the main difference?
  • Is inline code simply a "form" of macros?
  • What kind of tradeoff must be done when choosing to inline your code?

Thanks

like image 511
Marcos Bento Avatar asked Sep 25 '08 11:09

Marcos Bento


People also ask

Why would you want to use inline?

An inline function is one for which the compiler copies the code from the function definition directly into the code of the calling function rather than creating a separate set of instructions in memory. This eliminates call-linkage overhead and can expose significant optimization opportunities.

When should inline be used?

Inline functions are commonly used when the function definitions are small, and the functions are called several times in a program. Using inline functions saves time to transfer the control of the program from the calling function to the definition of the called function.

When inline method should not be used?

When we should avoid the use of inline? We should not use functions that are I/O bound as inline functions. When large code is used in some function, then we should avoid the inline. When recursion is used, inline function may not work properly.

Is inline necessary?

No, that does not matter at all. There are cases where it is appropriate to use inline in a .


7 Answers

Performance

As has been suggested in previous answers, use of the inline keyword can make code faster by inlining function calls, often at the expense of increased executables. “Inlining function calls” just means substituting the call to the target function with the actual code of the function, after filling in the arguments accordingly.

However, modern compilers are very good at inlining function calls automatically without any prompt from the user when set to high optimisation. Actually, compilers are usually better at determining what calls to inline for speed gain than humans are.

Declaring functions inline explicitly for the sake of performance gain is (almost?) always unnecessary!

Additionally, compilers can and will ignore the inline request if it suits them. Compilers will do this if a call to the function is impossible to inline (i.e. using nontrivial recursion or function pointers) but also if the function is simply too large for a meaningful performance gain.

One Definition Rule

However, declaring an inline function using the inline keyword has other effects, and may actually be necessary to satisfy the One Definition Rule (ODR): This rule in the C++ standard states that a given symbol may be declared multiple times but may only be defined once. If the link editor (= linker) encounters several identical symbol definitions, it will generate an error.

One solution to this problem is to make sure that a compilation unit doesn't export a given symbol by giving it internal linkage by declaring it static.

However, it's often better to mark a function inline instead. This tells the linker to merge all definitions of this function across compilation units into one definition, with one address, and shared function-static variables.

As an example, consider the following program:

// header.hpp
#ifndef HEADER_HPP
#define HEADER_HPP

#include <cmath>
#include <numeric>
#include <vector>

using vec = std::vector<double>;

/*inline*/ double mean(vec const& sample) {
    return std::accumulate(begin(sample), end(sample), 0.0) / sample.size();
}

#endif // !defined(HEADER_HPP)
// test.cpp
#include "header.hpp"

#include <iostream>
#include <iomanip>

void print_mean(vec const& sample) {
    std::cout << "Sample with x̂ = " << mean(sample) << '\n';
}
// main.cpp
#include "header.hpp"

void print_mean(vec const&); // Forward declaration.

int main() {
    vec x{4, 3, 5, 4, 5, 5, 6, 3, 8, 6, 8, 3, 1, 7};
    print_mean(x);
}

Note that both .cpp files include the header file and thus the function definition of mean. Although the file is saved with include guards against double inclusion, this will result in two definitions of the same function, albeit in different compilation units.

Now, if you try to link those two compilation units — for example using the following command:

⟩⟩⟩ g++ -std=c++11 -pedantic main.cpp test.cpp

you'll get an error saying “duplicate symbol __Z4meanRKNSt3__16vectorIdNS_9allocatorIdEEEE” (which is the mangled name of our function mean).

If, however, you uncomment the inline modifier in front of the function definition, the code compiles and links correctly.

Function templates are a special case: they are always inline, regardless of whether they were declared that way. This doesn’t mean that the compiler will inline calls to them, but they won’t violate ODR. The same is true for member functions that are defined inside a class or struct.

like image 57
Konrad Rudolph Avatar answered Sep 28 '22 22:09

Konrad Rudolph


  • Is there a big difference between "regular" code and inline code?

Yes and no. No, because an inline function or method has exactly the same characteristics as a regular one, most important one being that they are both type safe. And yes, because the assembly code generated by the compiler will be different; with a regular function, each call will be translated into several steps: pushing parameters on the stack, making the jump to the function, popping the parameters, etc, whereas a call to an inline function will be replaced by its actual code, like a macro.

  • Is inline code simply a "form" of macros?

No! A macro is simple text replacement, which can lead to severe errors. Consider the following code:

#define unsafe(i) ( (i) >= 0 ? (i) : -(i) )

[...]
unsafe(x++); // x is incremented twice!
unsafe(f()); // f() is called twice!
[...]

Using an inline function, you're sure that parameters will be evaluated before the function is actually performed. They will also be type checked, and eventually converted to match the formal parameters types.

  • What kind of tradeoff must be done when choosing to inline your code?

Normally, program execution should be faster when using inline functions, but with a bigger binary code. For more information, you should read GoTW#33.

like image 26
Luc Touraille Avatar answered Sep 28 '22 23:09

Luc Touraille


Inline code works like macros in essence but it is actual real code, which can be optimized. Very small functions are often good for inlining because the work needed to set up the function call (load the parameters into the proper registers) is costly compared to the small amount of actual work the method does. With inlining, there is no need to set up the function call, because the code is directly "pasted into" any method that uses it.

Inlining increases code size, which is its primary drawback. If the code is so big that it cannot fit into the CPU cache, you can get major slowdowns. You only need to worry about this in rare cases, since it is not likely you are using a method in so many places the increased code would cause issues.

In summary, inlining is ideal for speeding up small methods that are called many times but not in too many places (100 places is still fine, though - you need to go into quite extreme examples to get any significant code bloat).

Edit: as others have pointed out, inlining is only a suggestion to the compiler. It can freely ignore you if it thinks you are making stupid requests like inlining a huge 25-line method.

like image 22
Sander Avatar answered Sep 28 '22 22:09

Sander


  • Is there a big difference between "regular" code and inline code?

Yes - inline code does not involve a function call, and saving register variables to the stack. It uses program space each time it is 'called'. So overall it takes less time to execute because there's no branching in the processor and saving of state, clearing of caches, etc.

  • Is inline code simply a "form" of macros?

Macros and inline code share similarities. the big difference is that the inline code is specifically formatted as a function so the compiler, and future maintainers, have more options. Specifically it can easily be turned into a function if you tell the compiler to optimize for code space, or a future maintainer ends up expanding it and using it in many places in their code.

  • What kind of tradeoff must be done when choosing to inline your code?

    • Macro: high code space usage, fast execution, hard to maintain if the 'function' is long
    • Function: low code space usage, slower to execute, easy to maintain
    • Inline function: high code space usage, fast execution, easy to maintain

It should be noted that the register saving and jumping to the function does take up code space, so for very small functions an inline can take up less space than a function.

-Adam

like image 43
Adam Davis Avatar answered Sep 28 '22 22:09

Adam Davis


It depends on the compiler...
Say you have a dumb compiler. By indicating a function must be inlined, it will put a copy of the content of the function on each occurrence were it is called.

Advantage: no function call overhead (putting parameters, pushing the current PC, jumping to the function, etc.). Can be important in the central part of a big loop, for example.

Inconvenience: inflates the generated binary.

Is it a macro? Not really, because the compiler still checks the type of parameters, etc.

What about smart compilers? They can ignore the inline directive, if they "feel" the function is too complex/too big. And perhaps they can automatically inline some trivial functions, like simple getters/setters.

like image 36
PhiLho Avatar answered Sep 29 '22 00:09

PhiLho


Inline differs from macros in that it's a hint to the compiler (compiler may decide not to inline the code!) and macros are source code text generation before the compilation and as such are "forced" to be inlined.

like image 39
Kasprzol Avatar answered Sep 28 '22 23:09

Kasprzol


Marking a function inline means that the compiler has the option to include in "in-line" where it is called, if the compiler chooses to do so; by contrast, a macro will always be expanded in-place. An inlined function will have appropriate debug symbols set up to allow a symbolic debugger to track the source where it came from, while debugging macros is confusing. Inline functions need to be valid functions, while macros... well, don't.

Deciding to declare a function inline is largely a space tradeoff -- your program will be larger if the compiler decides to inline it (particularly if it isn't also static, in which case at least one non-inlined copy is required for use by any external objects); indeed, if the function is large, this could result in a drop in performance as less of your code fits in cache. The general performance boost, however, is just that you're getting rid of the overhead of the function call itself; for a small function called as part of an inner loop, that's a tradeoff that makes sense.

If you trust your compiler, mark small functions used in inner loops inline liberally; the compiler will be responsible for Doing The Right Thing in deciding whether or not to inline.

like image 35
Charles Duffy Avatar answered Sep 28 '22 23:09

Charles Duffy