Using C++ constructs in performance-critical code
Note: The discussion in this information applies to high-level language
constructs that might seriously degrade the performance of C++ programs.
All other coding discussions in this information apply to both C and C++ programs.
Be aware that in C++, more than in C, certain coding constructs can lead to n-to-1, m-to-1 or even z-to-1 code expansion. You can create well-performing code with these constructs, but you must use them carefully and appropriately, especially when you are writing critical-path or high-frequency code.
When writing performance-critical C++ programs, ensure that you understand why problems might occur and what you can do about them if you use any of the following high-level language constructs:
- Virtual
- The virtual construct is an important part of
object-oriented coding and can be very useful in removing the if and switch logic
from an application. Programmers often use virtual and
neglect to remove the switch logic. Note the following:
- The use of a virtual construct (like the use of a pointer and unlike the use of if statements) prevents the compiler from knowing how that construct is defined, which would provide the compiler with an optimization opportunity. In other words, when you use a virtual construct instead of if or switch statements, you limit optimization opportunities.
- In a non-XPLINK module, because of function overhead, virtual functions are costlier to execute than straight-line code with if or switch statements.
- Exception handling
- When exception handling is available (that is, when you are using
the EXH compiler option), opportunities for both normal optimizations
and for inlining are limited. This is because the compiler must generate
extra code to keep track of execution events and to ensure that all
required objects are caught by the correct routines. When you use the C++ try and catch blocks, the compiler creates obstacles to optimization. The compiler cannot pull common code out of a try block because it might trigger an exception that would need to be caught. Similarly, code cannot be pulled out of a catch block because:
- The code in a catch block is triggered far down the call chain, after the exception has occurred
- After a catch has occurred, the compiler must ensure that all requested tasks have been executed
You might improve compiler performance by:- Removing dependencies on C++ exception handling from your code
- Compiling with the NOEXH compiler option
- Dynamic casts/Runtime type identification (RTTI)
- A dynamic cast (also known as RTTI) is a coding construct that
delays, until run time, the determination of which code is to be executed.
This limits the potential for optimization. In addition, the process
of actually doing the dynamic cast involves multiple function calls
and large amounts of code. Note: We strongly recommend that RTTI/dynamic casts not be used in performance-critical code. You can often avoid the use of RTTI through careful application design.
- iostream
- As discussed in Using the Standard C++ Library I/O Stream Classes and in Using C and C++ standard streams and redirection, iostream is
often built upon the standard C I/O library (fprintf, fopen, fclose, fread, fwrite).
For I/O performance-critical portions of your application, it is often
faster to use the C I/O functions explicitly instead of iostream.
Note: You must be careful if you are mixing the C++ stream classes with the C library. For more information, see Using the Standard C++ Library I/O Stream Classes.
- Standard Template Library and other class libraries
- These libraries are very convenient and are often well coded, but you must remember that each use of a class can involve one or more function calls. If you keep this in mind when coding, you can design applications that use these libraries efficiently. For example, you would not initialize all local string variables to the NULL string and then redefine the string on first reference.
- new/delete
- New C++ applications
on z/OS® often
depend heavily on new and delete operators
because they are commonly one of the first things taught in a C++ introductory
course, and many courses never explicitly teach that classes can also
be automatic (default for local) or global variables. You should be aware that the new and delete operators are costlier to use than variables. Also, before using new, you should carefully consider:
- The scope/usage pattern of the variable
- Whether an automatic (local) or global variable is more appropriate
Note: You can ensure that all memory and storage requests are properly optimized by following the instructions given in Improving performance with compiler options and Optimizing memory and storage.