03.12.2012 Views

C++ for Scientists - Technische Universität Dresden

C++ for Scientists - Technische Universität Dresden

C++ for Scientists - Technische Universität Dresden

SHOW MORE
SHOW LESS

Create successful ePaper yourself

Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.

100 CHAPTER 4. GENERIC PROGRAMMING<br />

a new compilation <strong>for</strong> each combination of types. As a consequence, the sources must reside in<br />

header files and cannot be stored to libraries. 7<br />

Executable size: As mentioned be<strong>for</strong>e, generic functions need multiple compilations and<br />

as a result of this, the generated executable contains code <strong>for</strong> each instatiation. A function<br />

programmed against an abstract interface exist only once. On the other hand, the virtual<br />

functions introduce some additional memory need to store the virtual function tables. Except<br />

<strong>for</strong> some pathological examples, one can expect that this additional space is less than the extra<br />

space needed <strong>for</strong> having separate machine code <strong>for</strong> every instantiation of a generic function. In<br />

extreme cases, a very large executable size can negatively impact the per<strong>for</strong>mance due to waste<br />

of cache memory.<br />

Per<strong>for</strong>mance: The higher compilation ef<strong>for</strong>ts <strong>for</strong> generic programming has a double per<strong>for</strong>mance<br />

benefit. Functions within the multi-functional computations do not need to be called<br />

indirectly via expensive function pointers but can be called directly. Whenever appropriate they<br />

can be even inlined saving the function call overhead entirely. We once measured the impact<br />

of the approaches to the per<strong>for</strong>mance of an accumulate function (a more general approach than<br />

in § 4.2.1) [?]. The generic version was in our case about 40 times faster than the inheritancebased<br />

implementation. This value varies from plat<strong>for</strong>m to plat<strong>for</strong>m but <strong>for</strong> small functions<br />

one can expect that an inlined template function is 10–100 times faster than virtual functions.<br />

Conversely, <strong>for</strong> long calculations like solving a large linear system the per<strong>for</strong>mance difference is<br />

unperceivable.<br />

Concept refinement: that is adding (syntactic) requirements is feasible with the inheritance<br />

approach but it is very tedious and obfuscates the program source, details in [?].<br />

Intrusiveness: The genericity emulation by inheritance can induce a deep class hierarchy [?],<br />

more critical <strong>for</strong> the universal applicability is that the technology is intrusive. A type cannot<br />

be used as argument of an OOP implementation if it is not derived from the according class<br />

even if the provides the correct interface! Thus, we have to add additional base class(es) to the<br />

type. This is particularly problematic if we use types from third-party libraries or intrinsic types<br />

because we cannot add base classes their. Generic functions have not such rigid constraints. We<br />

can even adapt a third-party or intrinsic type to meet a generic function’s syntactic requirements<br />

without modifying third-party programs.<br />

Time of selection: At least one advantage of the OOP-style polymorphism we should mention<br />

at the end. The argument type of generic function call must be known at compile time so that<br />

the compiler can instantiate the template function. The type of an OOP function argument can<br />

be chosen during the execution of the program and there<strong>for</strong>e depend on preceeding calculations<br />

or input data. For instance, one can define in a file which linear solver is used in an application.<br />

Résumé: It is not our goal to compare object-oriented and generic programming in general.<br />

The two approaches complete each other in many respects and this is beyond the scope of this<br />

discussion. However, when only considering the aspect of maximal applicability with optimal<br />

per<strong>for</strong>mance the generic approach is undoubtly superior. Especially if functions of a library are<br />

used with types defined outside this library, possibly necessary interface adaption is quite easy<br />

without modifying the type definition while the addition of extra base classes <strong>for</strong>ces changing<br />

the type definition what is not always possible (or desirable). In contexts where functions are<br />

used with limited numbers of types and they are defined in the same library, derivation can be<br />

7 Libraries in the classical sense that are linked with separately compiled sources as opposed to template<br />

libraries.

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!