When the compiler inline-expands a function call, the function's code gets
inserted into the caller's code stream (conceptually similar to what happens
with a
There are several ways to designate that a function is inline, some of which involve the inline keyword, others do not. No matter how you designate a function as inline, it is a request that the compiler is allowed to ignore: it might inline-expand some, all, or none of the calls to an inline function. (Don't get discouraged if that seems hopelessly vague. The flexibility of the above is actually a huge advantage: it lets the compiler treat large functions differently from small ones, plus it lets the compiler generate code that is easy to debug if you select the right compiler options.)
[ Top | Bottom | Previous section | Next section | Search the FAQ ]
Consider the following call to function
Assuming a typical C++ implementation that has registers and a stack, the
registers and parameters get written to the stack just before the call to
If the compiler inline-expands the call to
Naturally your mileage may vary, and there are a zillion variables that are outside the scope of this particular FAQ, but the above serves as an example of the sorts of things that can happen with procedural integration.
[ Top | Bottom | Previous section | Next section | Search the FAQ ]
Yes and no. Sometimes. Maybe.
There are no simple answers. inline functions might make the code faster, they might make it slower. They might make the executable larger, they might make it smaller. They might cause thrashing, they might prevent thrashing. And they might be, and often are, totally irrelevant to speed.
inline functions might make it faster: As shown above, procedural integration might remove a bunch of unnecessary instructions, which might make things run faster.
inline functions might make it slower: Too much inlining might cause code bloat, which might cause "thrashing" on demand-paged virtual-memory systems. In other words, if the executable size is too big, the system might spend most of its time going out to disk to fetch the next chunk of code.
inline functions might make it larger: This is the notion of code bloat, as described above. For example, if a system has 100 inline functions each of which expands to 100 bytes of executable code and is called in 100 places, that's an increase of 1MB. Is that 1MB going to cause problems? Who knows, but it is possible that that last 1MB could cause the system to "thrash," and that could slow things down.
inline functions might make it smaller: The compiler often generates more code to push/pop registers/parameters than it would by inline-expanding the function's body. This happens with very small functions, and it also happens with large functions when the optimizer is able to remove a lot of redundant code through procedural integration that is, when the optimizer is able to make the large function small.
inline functions might cause thrashing: Inlining might increase the size of the binary executable, and that might cause thrashing.
inline functions might prevent thrashing: The working
set size (number of pages that need to be in memory at once) might go down
even if the executable size goes up. When
inline functions might increase the number of cache misses: Inlining might cause an inner loop to span across multiple lines of the memory cache, and that might cause thrashing of the memory-cache.
inline functions might decrease the number of cache misses: Inlining usually improves locality of reference within the binary code, which might decrease the number of cache lines needed to store the code of an inner loop. This ultimately could cause a CPU-bound application to run faster.
inline functions might be irrelevant to speed: Most systems are not CPU-bound. Most systems are I/O-bound, database-bound or network-bound, meaning the bottleneck in the system's overall performance is the file system, the database or the network. Unless your "CPU meter" is pegged at 100%, inline functions probably won't make your system faster. (Even in CPU-bound systems, inline will help only when used within the bottleneck itself, and the bottleneck is typically in only a small percentage of the code.)
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.
[ Top | Bottom | Previous section | Next section | Search the FAQ ]
In straight C, you can achieve "encapsulated structs" by putting a
Unfortunately it forfeits type safety, and also imposes a function call to
access even trivial fields of the struct (if you allowed direct access to the
struct's fields, anyone and everyone would be able to get direct access since
they would of necessity know how to interpret the stuff pointed to by the
Function call overhead is small, but can add up. C++ classes allow function
calls to be expanded inline. This lets you have the safety of encapsulation
along with the speed of direct access. Furthermore the parameter types of
these inline functions are checked by the compiler, an improvement over C's
[ Top | Bottom | Previous section | Next section | Search the FAQ ]
Because
Unlike
Also unlike macros, argument types are checked, and necessary conversions are performed correctly.
Macros are bad for your health; don't use them unless you have to.
[ Top | Bottom | Previous section | Next section | Search the FAQ ]
When you declare an inline function, it looks just like a normal function:
But when you define an inline function, you prepend the function's definition with the keyword inline, and you put the definition into a header file:
Note: It's imperative that the function's definition (the part between the
[ Top | Bottom | Previous section | Next section | Search the FAQ ]
When you declare an inline member function, it looks just like a normal member function:
But when you define an inline member function, you prepend the member function's definition with the keyword inline, and you put the definition into a header file:
It's usually imperative that the function's definition (the part between the
[ Top | Bottom | Previous section | Next section | Search the FAQ ]
Yep: define the member function in the class body itself:
Although this is easier on the person who writes the class, it's harder on all the readers since it mixes "what" a class does with "how" it does them. Because of this mixture, we normally prefer to define member functions outside the class body with the inline keyword. The insight that makes sense of this: in a reuse-oriented world, there will usually be many people who use your class, but there is only one person who builds it (yourself); therefore you should do things that favor the many rather than the few. This approach is further exploited in the next FAQ.
[ Top | Bottom | Previous section | Next section | Search the FAQ ]
Best practice: only in the definition outside the class body.
Here's the basic idea:
From a practical standpoint, this separation makes life easier and safer for
your users. Say Chuck wants to simply "use" your class. Because you read
this FAQ and used the above separation, Chuck can read your class's
Back to inline-ness: the decision of whether a function is or is not
inline is an implementation detail that does not change the observable
semantics (the "meaning") of a call. Therefore the inline keyword
should go next to the function's definition, not within the class's
NOTE: most people use the terms "declaration" and "definition" to differentiate the above two places. For example, they might say, "Should I put the inline keyword next to the declaration or the definition?" Unfortunately that usage is sloppy and somebody out there will eventually gig you for it. The people who gig you are probably insecure, pathetic wannabes who know they're not good enough to actually acomplish something with their lives, nonetheless you might as well learn the correct terminology to avoid getting gigged. Here it is: every definition is also a declaration. This means using the two as if they are mutually exclusive would be like asking which is heavier, steel or metal? Almost everybody will know what you mean if you use "definition" as if it is the opposite of "declaration," and only the worst of the techie weenies will gig you for it, but at least you now know how to use the terms correctly.
[ Top | Bottom | Previous section | Next section | Search the FAQ ]
E-mail the author
[ C++ FAQ Lite
| Table of contents
| Subject index
| About the author
| ©
| Download your own copy ]
Revised Mar 1, 2006