Der Compiler kann wirklich ganz viel Optimieren, solange er das komplette Programm als Code sehen kann. Wird irgendwo eine Funktion aus einer Laufzeit-Bibliothek aufgerufen, ist es vorbei mit der Optimierung. Ein kleines Beispiel soll das verdeutlichen:
void foo(const int &x); int bar() { int x = 0; int y = 0; for (int i = 0; i < 10; i++) { foo(x); y += x; } return y; }
Die Funktion foo ist nicht definiert, das gäbe einen Linker Error. Wichtig ist erst einmal, dass zur Compilezeit nicht bekannt ist, was die funktion foo tut. Dementsprechend können keine Annahmen getroffen werden um weitere Optimierungen vorzunehmen. Die Assembercode sieht aus wie erwartet:
bar(): pushq %rbp // safe register rbp rbx pushq %rbx subq $24, %rsp // allocate memory on stack movl $0, 12(%rsp) // x=0 movl $10, %ebx // i=10 movl $0, %ebp // y=0 .L2: // for... leaq 12(%rsp), %rdi call foo(int const&) addl 12(%rsp), %ebp // y += x subl $1, %ebx // --i jne .L2 movl %ebp, %eax // return y addq $24, %rsp // release memory on stack popq %rbx // restore register popq %rbp ret
Der C++ Code wurde quasi 1:1 in Assember umgesetzt. Nichts besonderes.
Wenn jetzt die Funktion bar() bekannt ist und zum Beispiel einfach eine leere Funktion ist, ändern die etwas am erzeugten Assembler Code? Allerdings!
foo(int const&): ret bar(): movl $0, %eax ret
Der Compiler hat quasi alles weg-optimiert. Der Funktionsaufruf von foo(), die Addition von y, die Schleife. Das sichern der Register ist nicht mehr notwenig. Stack Speicher wird nicht genutzt. Der Compiler hat erkannt, dass die Funktion immer 0 zurück gibt.
Also: benutzt templates und inline, statt klassische Bibliotheks-Funktions-Aufrufe.