This chapter describes how to trade program size for performance and vice versa. There are many things that can make a program unnecessarily large. Among them are:
unneeded code is linked with the program,
program code or data is duplicated.
Too extensive copying of code will make a program hard to maintain and will increase the size of the program. Therefore it should be a goal to reuse code to a large extent.
There is a trade-off between the size of an executable and its performance. Inline functions can make a program faster, but since many inline functions will increase the size of a program, the effect could be the opposite.
Before making a function inline it is necessary to check if the need for inlining really exists.
Rec 14.1 Avoid duplicated code and data.
Rule 14.2 When a public base class has a virtual destructor, each derived class should declare and implement a destructor.
Rec 7.1 , when to make functions inline .
Rule 10.4 , how to declare destructors for derived classes.
Rec 14.1 Avoid duplicated code and data.
Large programs can have negative consequences on the overall performance of a system. If an operating system with multi-tasking is used, each program must share the CPU with other programs. If the program is large, that means it is less likely that the program can stay in memory while the operating system runs other programs. More time will be spent in swapping programs in and out of memory, since the time for context switches will increase. Reading pages of large programs from memory is time consuming. This can reduce the amount of actual work that is done by a program during a time slot.
Without proper care when implementing and using classes, many programs could become unnecessarily large.
Reuse of code has the benefit of making a program more easy to maintain. An additional benefit is better quality, since code that is reused has been tested at least once. In theory, reuse should make a program smaller, but a common problem is that many class libraries will give the client a larger executable instead. A problem is that most linkers will link a function even if it is not called by the program. The result will be a code bloat that can only be avoided by carefully organizing the source code. The problem could partially be solved by putting each function definition in its own implementation file. Not even this kind of drastic solution is complete since all virtual functions that a program potentially can use must be linked. Since these are called indirectly, the compiler has no way of knowing exactly which ones that are not needed.
All these problems are technical an will probably be solved in the future. Try to reuse code to a large extent, since there is good chance that you can get better and smaller programs.
The program size will also depend on how different compilers treat inline functions.
It is possible to speed up the program by using inline functions, but if these make the program too large, the effect will be the opposite. There is a trade-off between inlining and program size that must be taken seriously.
The inline keyword is a hint to the compiler to inline-expand the function body where the function is called. Inline functions are not meant to be called as ordinary functions, but sometimes the compiler is unable to inline-expand them, and in such cases the compiler will generate a function with local linkage that can be called by programs. This generated function is similar to a static function, i.e. it can only be called inside the file that defines it.
Inline-expansion could fail if the inline function contains loops, if the address of an inline function is used, or if an inline function is called in a complex expression. In these cases, the compiler will not be able to inline-expand the function. The rules for inlining are compiler-dependent, but to be on the safe side, avoid the cases mentioned here.
Since the generated functions have local linkage, the compiler will generate many copies of the function; one for each implementation file that includes the header file with its definition. The total amount of code generated could become large, unless the linker is smart enough to remove excessive copies. Unfortunately, not all linkers are that smart. The general recommendation is therefore to only declare functions as inline if they are actually inline-expanded.
Constructors and destructors are often too complex for inlining even though they appear to be simple. Do not forget that constructors and destructors for the base class and data members are called implicitly.
Virtual member functions could often be simple enough for inlining, but they should not be declared inline .
Rule 14.2 When a public base class has a virtual destructor, each derived class should declare and implement a destructor.
A particularly insidious case, worth making a special rule for, concerns destructors. Destructors are the only virtual functions that could be generated by the compiler. If a base class declares and implements a virtual destructor and if a derived class does not provide one, the compiler will need to generate a destructor for the derived class.
A compiler needs to store the address of all virtual member functions, to make it possible to bind their calls dynamically. This includes the destructor. Some compilers use the location of the first virtual member function to decide where to allocate the virtual table (a table that stores addresses of virtual member functions). This is dangerous since there could be many such locations if the destructor is the first virtual member function and it has been generated by the compiler. Some compilers will duplicate the virtual table if there is more than one location. This could significantly increase the size of your program.
You should either avoid making the destructor the first virtual member function, or make sure that each derived class declares and implements it. The latter solution is better, since it is portable. Another compiler could, for example, instead use the address of the last virtual member function to determine where to allocate the virtual table.