Why should I ever use inline code?
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.
- 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.