C schneller als C++
-
Ich denke er meint sowas:
const int i = ...; void Foo() { UseValue(i); // load i ExternalFunction(); UseValue(i); // load i kann hier entfallen, da das *Objekt* i selbst const ist, und ein Objekt das selbst const ist darf man nicht ändern (wäre UB) }
Ohne
const
muss der Compiler hier nachExternalFunction()
wieder einen neuen Load auf i reinmachen. Mitconst
eben nicht.const_cast
etc. ist ja nur erlaubt wenn das Programm sicherstellt dass das eigentliche Objekt nicht const ist, sondern nur die Referenz mit der man gerade arbeitet.
Und obExternalFunction()
irgendwelche Register verwendet, ist dann doch vollkommen egal. Nicht?
-
hustbaer schrieb:
Und ob
ExternalFunction()
irgendwelche Register verwendet, ist dann doch vollkommen egal. Nicht?Wenn die Calling Convention besagt, dass der Aufgerufene alle Register ändern darf, ist
i
natürlich so oder so weg und muss neu geladen werden. Wenni
const
ist, kann der Compiler eine Kopie davon auf dem Stack ablegen und nach dem Aufruf diese Kopie laden, um auszunutzen, dass der Stack sowieso hot ist undi
vielleicht schon cold.
Das sind natürlich eher theoretische Überlegungen und ich bezweifle, dass irgendein Compiler außer Intel so etwas macht.
Ich möchte damit nur zeigen, dassconst
für den Optimizer nicht wertlos ist.
-
Nachdem alle Calling-Conventions die mir geläufig sind nicht erlauben alle Register flachzubügeln, ist das garantiert keine theoretische Überlegung sondern eine ganz praktische.
Einen Wert über einen Funktionsaufruf hinweg in einem Register zu halten sollte ja wohl wirklich *jeder* Compiler schaffen.Weswegen es auch so wichtig ist dem Compiler zu ermöglichen zu wissen dass ein Funktionsaufruf bestimmte Objekte nicht ändern *kann*. Nicht nur globale/static const Objekte, sondern vor allem auch lokale Objekte.
Sobald man deren Adresse nämlich irgendwohin kommuniziert, wo der Compiler nicht sicher sein kann was mit der Information alles angestellt wird, muss er auch bei lokalen Objekten annehmen dass sie von opaken Funktionen geändert wurden.
-
hustbaer schrieb:
Sobald man deren Adresse nämlich irgendwohin kommuniziert, wo der Compiler nicht sicher sein kann was mit der Information alles angestellt wird, muss er auch bei lokalen Objekten annehmen dass sie von opaken Funktionen geändert wurden.
Ein anderes Beispiel für das Prinzip sind Arrays:
extern void f(int &); std::array<int, 2> a; f(a[0]); //a[1] kann sich geändert haben, weil man mit Zeigern in Arrays rechnen darf int a0, a1; f(a0); //a1 kann sich nicht geändert haben
Das müsste auch bei Strukturen gelten:
struct S //außerhalb der Funktion deklariert { int a0; int a1; }; S s; f(s.a0); //s.a1 kann sich geändert haben, weil f eine Referenz auf das erste //Element eines PODs auf den POD-Typ casten darf. Ist zumindest in C so. struct { int a0; int a1; } s; f(a.a0); //s.a1 kann sich nicht geändert haben, weil der Typ der Struktur in //f nicht bekannt sein kann. Richtig? Strict Aliasing verbietet es eine äquivalente Struktur für den Zugriff zu benutzen.
Das "pay for what you use"-Prinzip sollte man in C++ vorsichtig zitieren. Es gibt so viele Beispiele für guten Code, der ohne einen allwissenden Optimizer nicht optimal laufen kann.