C++ for Scientists - Technische Universität Dresden
C++ for Scientists - Technische Universität Dresden C++ for Scientists - Technische Universität Dresden
40 CHAPTER 2. C++ BASICS 2.6.1 Inline Functions Calling a function requires a fair amount of activities: • The arguments (or at least their addresses) must be copied on the stack; • The current program counter must be copied on the stack to continue the execution at this point when the function is finished; • Save registers to allow the function using them; • Jump to the code of the function; • Execute the function; • Clean the arguments from the stack; • Copy the result on the stack; • Jump back to the calling code; • Store back registers. What happens exactly depends on the hardware. The good news is that the function call overhead is dramatically lower than in the past. Furthermore, the compiler can optimize out those activities not needed in a specific call. Nonetheless, for small functions, like the square above, the effort for calling the function is still significantly higher than what the function actually does. C programmers avoid the function-call overhead by macros. Macros create so many problems in the software development that they must only be used when there is absolutely no alternative whatsoever. Bjarne Stroustrup says “Almost every macro demonstrates a flaw in the programming language, in the program, or in the programmer.” We like to add a flaw “in the compiler optimization”. 16 Fortunately, we have an excellent alternative to macros: inline functions. The programmer just adds the keyword inline to the function definition: inline double square(double x) { return x ∗ x; } and all the overhead of the function call vanishes into thin air. An excessive use of inline can have a negative effect on performance. When many large functions are inlined then the binary executable becomes very large. The consequence is that a lot of time is spend loading the binary from memory and lots of cache memory is wasted for it as well. This decreases the memory bandwidth and cache available for data, causing more slow down than what is saved on function calls. 16 Advanced: Compilers are today really smart in eliminating unused code. However, we experienced that arguments of inline functions might be constructed although they are not used. This are usually only few machine instructions. But when this happens extremely frequently as in an index range check that should disappear in release mode, it can ruin the overall performance. We hope that further compiler improvement can rescue us from this kind of macro usage.
2.6. FUNCTIONS 41 It should be mentioned here that the inline keyword is not mandatory. The compiler can decide against inlining for the reasons given in the previous paragraph. On the other hand, the compiler is free to inline functions without the inline keyword. For obvious reasons, the definition of an inline function must be visible in every compile unit where it is called. In contrast to other functions, it cannot be compiled separately. Conversely, a non-inline function cannot be visible in multiple compile units because it collides when the compiled parts are ‘linked’ together. Thus, there are two ways to avoid such collisions: assuring that the function definition is only present in one compile unit or declaring the function as inline. 2.6.2 Function Arguments If we pass an argument to a function it creates by default a copy. For instance, the following would not work (as expected): void increment(int x) { x++; } int main() { int i= 4; increment(i); cout ≪ ”i is ” ≪ i ≪ ’\n’; } The output would be 4. The operation x++ in the second line only increments a local copy but not the original value. This kind of argument transfer is called ‘call-by-value’ or ‘pass-by-value’. To modify the value itself we have to ‘pass-by-reference’ the variable: void increment(int& x) { x++; } Now the variable itself is increment and the output will be 5 as expected. We will discuss references more detailed in § 2.10.2. Temporary variables — like the result of an operation — cannot be passed by reference: increment(i + 9); // error We could not compute (i + 9)++ anyway. In order to call such a function with some temporary value one needs to store it first in a variable and pass this variable to the function. Larger data structures like vectors and matrices are almost always passed by reference for avoiding expensive copy operations: double two norm(vector& v) { ... } An operation like a norm should not change its argument. But passing the vector by reference bears the risk of accidentally overwriting it.
- Page 1 and 2: Technische Universität Dresden Fak
- Page 3 and 4: Contents I Understanding C++ 7 Intr
- Page 5 and 6: CONTENTS 5 10.5 Unix and Linux . .
- Page 7: Part I Understanding C ++ 7
- Page 10 and 11: 10 C ++ was not a reliable computer
- Page 12 and 13: 12 CHAPTER 1. GOOD AND BAD SCIENTIF
- Page 14 and 15: 14 CHAPTER 1. GOOD AND BAD SCIENTIF
- Page 16 and 17: 16 CHAPTER 1. GOOD AND BAD SCIENTIF
- Page 18 and 19: 18 CHAPTER 1. GOOD AND BAD SCIENTIF
- Page 20 and 21: 20 CHAPTER 2. C++ BASICS • std::c
- Page 22 and 23: 22 CHAPTER 2. C++ BASICS In the fir
- Page 24 and 25: 24 CHAPTER 2. C++ BASICS int main (
- Page 26 and 27: 26 CHAPTER 2. C++ BASICS Operator A
- Page 28 and 29: 28 CHAPTER 2. C++ BASICS The bitwis
- Page 30 and 31: 30 CHAPTER 2. C++ BASICS cast (type
- Page 32 and 33: 32 CHAPTER 2. C++ BASICS complicate
- Page 34 and 35: 34 CHAPTER 2. C++ BASICS } else if
- Page 36 and 37: 36 CHAPTER 2. C++ BASICS eps/= 2.0;
- Page 38 and 39: 38 CHAPTER 2. C++ BASICS for (...;
- Page 42 and 43: 42 CHAPTER 2. C++ BASICS To make su
- Page 44 and 45: 44 CHAPTER 2. C++ BASICS float divi
- Page 46 and 47: 46 CHAPTER 2. C++ BASICS The first
- Page 48 and 49: 48 CHAPTER 2. C++ BASICS #ifndef at
- Page 50 and 51: 50 CHAPTER 2. C++ BASICS float A[7]
- Page 52 and 53: 52 CHAPTER 2. C++ BASICS Encapsulat
- Page 54 and 55: 54 CHAPTER 2. C++ BASICS As a pract
- Page 56 and 57: 56 CHAPTER 2. C++ BASICS A function
- Page 58 and 59: 58 CHAPTER 2. C++ BASICS Now that t
- Page 60 and 61: 60 CHAPTER 2. C++ BASICS we need sm
- Page 62 and 63: 62 CHAPTER 2. C++ BASICS 2.12 Exerc
- Page 64 and 65: 64 CHAPTER 2. C++ BASICS 2.13 Opera
- Page 66 and 67: 66 CHAPTER 3. CLASSES apply symm bl
- Page 68 and 69: 68 CHAPTER 3. CLASSES int main() {
- Page 70 and 71: 70 CHAPTER 3. CLASSES class solver
- Page 72 and 73: 72 CHAPTER 3. CLASSES • Compilers
- Page 74 and 75: 74 CHAPTER 3. CLASSES a real number
- Page 76 and 77: 76 CHAPTER 3. CLASSES } return ∗t
- Page 78 and 79: 78 CHAPTER 3. CLASSES This mechanis
- Page 80 and 81: 80 CHAPTER 3. CLASSES One could not
- Page 82 and 83: 82 CHAPTER 3. CLASSES class matrix
- Page 84 and 85: 84 CHAPTER 3. CLASSES Approach 3: R
- Page 86 and 87: 86 CHAPTER 3. CLASSES of the decrem
- Page 88 and 89: 88 CHAPTER 3. CLASSES There are two
2.6. FUNCTIONS 41<br />
It should be mentioned here that the inline keyword is not mandatory. The compiler can decide<br />
against inlining <strong>for</strong> the reasons given in the previous paragraph. On the other hand, the compiler<br />
is free to inline functions without the inline keyword.<br />
For obvious reasons, the definition of an inline function must be visible in every compile unit<br />
where it is called. In contrast to other functions, it cannot be compiled separately. Conversely,<br />
a non-inline function cannot be visible in multiple compile units because it collides when the<br />
compiled parts are ‘linked’ together. Thus, there are two ways to avoid such collisions: assuring<br />
that the function definition is only present in one compile unit or declaring the function as<br />
inline.<br />
2.6.2 Function Arguments<br />
If we pass an argument to a function it creates by default a copy. For instance, the following<br />
would not work (as expected):<br />
void increment(int x)<br />
{<br />
x++;<br />
}<br />
int main()<br />
{<br />
int i= 4;<br />
increment(i);<br />
cout ≪ ”i is ” ≪ i ≪ ’\n’;<br />
}<br />
The output would be 4. The operation x++ in the second line only increments a local copy but<br />
not the original value. This kind of argument transfer is called ‘call-by-value’ or ‘pass-by-value’.<br />
To modify the value itself we have to ‘pass-by-reference’ the variable:<br />
void increment(int& x)<br />
{<br />
x++;<br />
}<br />
Now the variable itself is increment and the output will be 5 as expected. We will discuss<br />
references more detailed in § 2.10.2.<br />
Temporary variables — like the result of an operation — cannot be passed by reference:<br />
increment(i + 9); // error<br />
We could not compute (i + 9)++ anyway. In order to call such a function with some temporary<br />
value one needs to store it first in a variable and pass this variable to the function.<br />
Larger data structures like vectors and matrices are almost always passed by reference <strong>for</strong><br />
avoiding expensive copy operations:<br />
double two norm(vector& v) { ... }<br />
An operation like a norm should not change its argument. But passing the vector by reference<br />
bears the risk of accidentally overwriting it.