When should I write the keyword 'inline' for a function/method?
Oh man, one of my pet peeves.
inline
is more like static
or extern
than a directive telling the compiler to inline your functions. extern
, static
, inline
are linkage directives, used almost exclusively by the linker, not the compiler.
It is said that inline
hints to the compiler that you think the function should be inlined. That may have been true in 1998, but a decade later the compiler needs no such hints. Not to mention humans are usually wrong when it comes to optimizing code, so most compilers flat out ignore the 'hint'.
static
- the variable/function name cannot be used in other translation units. Linker needs to make sure it doesn't accidentally use a statically defined variable/function from another translation unit.extern
- use this variable/function name in this translation unit but don't complain if it isn't defined. The linker will sort it out and make sure all the code that tried to use some extern symbol has its address.inline
- this function will be defined in multiple translation units, don't worry about it. The linker needs to make sure all translation units use a single instance of the variable/function.
Note: Generally, declaring templates inline
is pointless, as they have the linkage semantics of inline
already. However, explicit specialization and instantiation of templates require inline
to be used.
Specific answers to your questions:
When should I write the keyword 'inline' for a function/method in C++?
Only when you want the function to be defined in a header. More exactly only when the function's definition can show up in multiple translation units. It's a good idea to define small (as in one liner) functions in the header file as it gives the compiler more information to work with while optimizing your code. It also increases compilation time.
When should I not write the keyword 'inline' for a function/method in C++?
Don't add inline just because you think your code will run faster if the compiler inlines it.
When will the compiler not know when to make a function/method 'inline'?
Generally, the compiler will be able to do this better than you. However, the compiler doesn't have the option to inline code if it doesn't have the function definition. In maximally optimized code usually all
private
methods are inlined whether you ask for it or not.As an aside to prevent inlining in GCC, use
__attribute__(( noinline ))
, and in Visual Studio, use__declspec(noinline)
.Does it matter if an application is multithreaded when one writes 'inline' for a function/method?
Multithreading doesn't affect inlining in any way.
I'd like to contribute to all of the great answers in this thread with a convincing example to disperse any remaining misunderstanding.
Given two source files, such as:
inline111.cpp:
#include <iostream> void bar(); inline int fun() { return 111; } int main() { std::cout << "inline111: fun() = " << fun() << ", &fun = " << (void*) &fun; bar(); }
inline222.cpp:
#include <iostream> inline int fun() { return 222; } void bar() { std::cout << "inline222: fun() = " << fun() << ", &fun = " << (void*) &fun; }
Case A:
Compile:
g++ -std=c++11 inline111.cpp inline222.cpp
Output:
inline111: fun() = 111, &fun = 0x4029a0 inline222: fun() = 111, &fun = 0x4029a0
Discussion:
Even thou you ought to have identical definitions of your inline functions, C++ compiler does not flag it if that is not the case (actually, due to separate compilation it has no ways to check it). It is your own duty to ensure this!
Linker does not complain about One Definition Rule, as
fun()
is declared asinline
. However, because inline111.cpp is the first translation unit (which actually callsfun()
) processed by compiler, the compiler instantiatesfun()
upon its first call-encounter in inline111.cpp. If compiler decides not to expandfun()
upon its call from anywhere else in your program (e.g. from inline222.cpp), the call tofun()
will always be linked to its instance produced from inline111.cpp (the call tofun()
inside inline222.cpp may also produce an instance in that translation unit, but it will remain unlinked). Indeed, that is evident from the identical&fun = 0x4029a0
print-outs.Finally, despite the
inline
suggestion to the compiler to actually expand the one-linerfun()
, it ignores your suggestion completely, which is clear becausefun() = 111
in both of the lines.
Case B:
Compile (notice reverse order):
g++ -std=c++11 inline222.cpp inline111.cpp
Output:
inline111: fun() = 222, &fun = 0x402980 inline222: fun() = 222, &fun = 0x402980
Discussion:
This case asserts what have been discussed in Case A.
Notice an important point, that if you comment out the actual call to
fun()
in inline222.cpp (e.g. comment outcout
-statement in inline222.cpp completely) then, despite the compilation order of your translation units,fun()
will be instantiated upon it's first call encounter in inline111.cpp, resulting in print-out for Case B asinline111: fun() = 111, &fun = 0x402980
.
Case C:
Compile (notice -O2):
g++ -std=c++11 -O2 inline222.cpp inline111.cpp
or
g++ -std=c++11 -O2 inline111.cpp inline222.cpp
Output:
inline111: fun() = 111, &fun = 0x402900 inline222: fun() = 222, &fun = 0x402900
Discussion:
- As is described here,
-O2
optimization encourages compiler to actually expand the functions that can be inlined (Notice also that-fno-inline
is default without optimization options). As is evident from the outprint here, thefun()
has actually been inline expanded (according to its definition in that particular translation unit), resulting in two differentfun()
print-outs. Despite this, there is still only one globally linked instance offun()
(as required by the standard), as is evident from identical&fun
print-out.
- As is described here,
You still need to explicitly inline your function when doing template specialization (if specialization is in .h file)