Efficiency has always been important to programmers. It is one of the key pillars in the tradition of C and C++, in which the guiding principle of "you shouldn't pay for what you don't use"—also known as the zero-cost principle—has always been at the forefront of the language's and library's design, and has been largely achieved.
This section, along with the two appendixes at the end of the book, takes a hard look at a few key C++ optimization issues selected for their real-world impact. When and how should you optimize your code? What does
inline
do, really? Why can (and do) fancy optimizations get us into trouble? Finally, and to me most interestingly, how can some of these answers change if you're writing multithread-safe code? After all, we're interested in efficiency issues in the real world, and although the C++ standard is silent about threads, more and more programmers in the trenches are writing multithreaded C++ code every day. And they will care about the answers.Item 12. inline
Difficulty: 4Contrary to popular opinion, the keyword
inline
is not some sort of magic bullet. It is, however, a useful tool when employed properly. The question is: When should you use it?1. What does
inline
do?2. Does making a function
inline
increase efficiency? 3. When and how should you decide toinline
a function?Solution
1. What does
inline
do?Making a function
inline
directs the compiler that it may choose to place a copy of the function's code directly into each place the code is used. In the cases where the compiler does so, it avoids generating a function call.2. Does making a function
inline
increase efficiency?Not necessarily.
First off, if you tried to answer this question without first asking what you want to optimize, you fell into a classic trap. The first question has to be: "What do you mean by efficiency?" Does the above question mean program size? Memory footprint? Execution time? Development speed? Build time? Or something else?
Second, contrary to popular opinion, inlining can improve or worsen any of those aspects of efficiency: a. Program size. Many programmers assume that inlining increases program size, because
instead of having one copy of a function's code, the compiler creates a copy in every place that function is used. This is often true, but not always. If the function size is smaller than the code the compiler has to generate to perform the function call, inlining will reduce program size.
b. Memory footprint. Inlining usually has little or no effect on a program's memory usage, apart from the basic program size (above).
c. Execution time. Many programmers assume that inlining a function will improve execution time because it avoids the function call overhead, and because "seeing through the veil" of the function call gives the compiler's optimizer more opportunities to work its craft. This can be true, but often isn't. If the function is not called extremely frequently, there will usually be no visible improvement in overall program execution time. In fact, just the opposite can happen. If inlining increases a calling function's size, it will reduce that caller's locality of reference, which means that overall program speed can actually worsen if the caller's inner loop no longer fits in the processor's cache.
To put this point in perspective, don't forget that most programs are not CPU-bound. Probably the most common bottleneck is being I/O-bound, which can include anything from network bandwidth or latency to file or database access.
d. Development speed, build time. To be most useful,
inline
d code has to be visible to the caller, which means that the caller has to depend on the internals of theinline
d code. Depending on another module's internal implementation details increases the practical coupling of modules (it does not, however, increase their theoretical coupling, because thecaller doesn't actually use any of the callee's internals). Usually, when functions change, callers do not need to be recompiled, only relinked. When
inline
d functions change, callers are forced to recompile. What's more, there's a completely separate hit on development speed that appears at debugging time, because stepping into inlined functions and managing breakpoints inside them tends to be more difficult for most debuggers.There is one case in which inlining a function can arguably be viewed as an optimization for development speed—when the cost of writing an accessor function (see below) would otherwise be too high to justify the good practice of providing an accessor function to avoid making a data member public. In this case, some would argue that
inline
encourages good coding style and better module insulation.Finally, if you're looking to improve efficiency in some way, always look to your algorithms and data structures first. They will give you the order-of-magnitude overall improvements, whereas process optimizations, such as inlining, generally (note, generally) yield less-dramatic results.