Wird const eigentlich optimiert?
-
shadow schrieb:
...
Hi, mir ging es eigentlich darum ob es nicht für den compiler besser ist wenn er während der Optimierphase weiß dass das argument const ist. Damit hätte er i.d.R. mehr Möglichkeiten zu optimieren. Dachte ich zumindest.
-
shadow schrieb:
const macht nur im Zusammenhang mit Pointern Sinn, da bei den normalen "primitiven" Datentypen sowieso eine Übergabe "by value" stattfindet.
Besser:
constbei Parametern mach nur bei Referenzen und Zeigern sinn. Ansonsten wird der übergebene Wert sowieso kopiert.
-
Welche kluge Kopf sagte das nochmal? "Optimiere erst, wenn es wirklich erforderlich ist. Optimierungen während der Implementation machen wenig Sinn und verkomplizieren die eigentlich simple Lösung."
Also meiner Meinung nach machst du dir da zu viele Gedanken. Außerdem ist das dann von Compiler zu Compiler unterschiedlich. Genieße einfach die Freude am hacken und mach dir erst einen dicken Kopp' wenn gar nüx geht

@EOutOfResources_At_Work
Ja, natürlich nur bei Parametern
-
const_versprechen schrieb:
Ich habe hier oft im Forum gelesen dass so etwas nicht gern gesehen wird:
void func(const double, const double);Das liegt in diesem Fall daran, dass das const an dieser Stelle keinerlei Bedeutung hat. In aller Regel ist es keine gute Idee bedeutungslose Sachen hinzuschreiben. Es ist z.B. auch möglich
const volatile foo();zu benutzen. Dieses const und volatile bleibt sogar Teil des Funktionstyps (im Gegensatz zur Qualifizierung von Parametern). Allerdings hat ein Ausdruck, der diese Funktion aufruft, trotzdem nur den Typ void und nicht const volatile void.
-
camper schrieb:
Das liegt in diesem Fall daran, dass das const an dieser Stelle keinerlei Bedeutung hat.
Doch, es hat eine Bedeutung:
void Func(const int P) { P = 5; //Geht nicht } void Func(int P) { P = 5; //Geht }Rein semantisch hat es also eine Bedeutung.
-
EOutOfResources_At_Work schrieb:
camper schrieb:
Das liegt in diesem Fall daran, dass das const an dieser Stelle keinerlei Bedeutung hat.
Doch, es hat eine Bedeutung:
void Func(const int P) { P = 5; //Geht nicht } void Func(int P) { P = 5; //Geht }Rein semantisch hat es also eine Bedeutung.
Das ist eine ganz anderere Frage. Der OP hat uns eine Funktionsdeklaration gezeigt.
-
SeppJ schrieb:
const gibt dir keine Vorteile bei der Optimierung.
Doch, klar ermöglicht const besseres Optimieren.
Globales Zeugs (auch static in Klassen/Funktionen) mit integralem Typ kann mit const als Comiletime-Konstante behandelt werden, ohne const nicht.
-
hustbaer schrieb:
Doch, klar ermöglicht const besseres Optimieren.
Globales Zeugs (auch static in Klassen/Funktionen) mit integralem Typ kann mit const als Comiletime-Konstante behandelt werden, ohne const nicht.
Struppi bezeichnet es doch "Konstante Ausdrücke auswerten". Deshalb geht die Sache mit TMP auch...
-
hustbaer schrieb:
Globales Zeugs (auch static in Klassen/Funktionen) mit integralem Typ kann mit const als Comiletime-Konstante behandelt werden, ohne const nicht.
Was genau hat das mit Optimieren zu tun?
-
Ich finde das const-Thema auch sehr verwirrend, darum nochmal ein paar Fragen:
SeppJ schrieb:
Und das mit den const-Funktionsparametern: Du bringst damit Implementierungsdetails nach außen, die niemanden interessieren und eventuell sogar verwirren.
Kannst du das nochmal etwas genauer erklären? Wieso sind hier nach außen Implementierungsdetails sichtbar?
void func(const double, const double);shadow schrieb:
Welche kluge Kopf sagte das nochmal? "Optimiere erst, wenn es wirklich erforderlich ist. Optimierungen während der Implementation machen wenig Sinn und verkomplizieren die eigentlich simple Lösung."
Den Satz halte ich persönlich für unsinnig. Wieso sollte ich mir die Arbeit machen im Nachhinein den Code nochmal optimieren zu müssen. Man ist dann teilweise nicht mehr im Thema drin, muss sich neu einarbeiten. Und jeder, der schonmal in seinem Projekt nachträglich mit const hantiert hat, wird die Erfahrung gamacht haben, dass plötzlich an 100 anderen Stellen ebenfalls const nötig wurde. Ich will aus Prinzip immer die optimale Lösung auch wenn es keinen wirklichen Performancevorteil verspricht ;).
EOutOfResources_At_Work schrieb:
Besser:
constbei Parametern mach nur bei Referenzen und Zeigern sinn. Ansonsten wird der übergebene Wert sowieso kopiert.Ich nehme mal an das gilt auch für die Rückgabetypen? Oder ist das const hier unsinnig.
const Object* MyFunc(); const Object& MyFunc();Und sollte man (wie z.B. bei Qt) Getter-funktionen immer als const definieren?
QSize minimumSizeHint() const; int heightForWidth(int) const;
-
StellerFragen schrieb:
SeppJ schrieb:
Und das mit den const-Funktionsparametern: Du bringst damit Implementierungsdetails nach außen, die niemanden interessieren und eventuell sogar verwirren.
Kannst du das nochmal etwas genauer erklären? Wieso sind hier nach außen Implementierungsdetails sichtbar?
void func(const double, const double);Ich vermute, SeppJ meint, dass hier gezeigt wird, dass ich intern die Parameter nicht verändere. Genau weiß ich es aber auch nicht.
StellerFragen schrieb:
shadow schrieb:
Welche kluge Kopf sagte das nochmal? "Optimiere erst, wenn es wirklich erforderlich ist. Optimierungen während der Implementation machen wenig Sinn und verkomplizieren die eigentlich simple Lösung."
Den Satz halte ich persönlich für unsinnig. Wieso sollte ich mir die Arbeit machen im Nachhinein den Code nochmal optimieren zu müssen. Man ist dann teilweise nicht mehr im Thema drin, muss sich neu einarbeiten. Und jeder, der schonmal in seinem Projekt nachträglich mit const hantiert hat, wird die Erfahrung gamacht haben, dass plötzlich an 100 anderen Stellen ebenfalls const nötig wurde. Ich will aus Prinzip immer die optimale Lösung auch wenn es keinen wirklichen Performancevorteil verspricht ;).
const ist ja auch nicht unbedingt eine Optimierung, sondern fällt eher unter "Korrektheit". Ich würde immer versuchen, so korrekt wie möglich zu programmieren, dazu gehört auch const.
StellerFragen schrieb:
EOutOfResources_At_Work schrieb:
Besser:
constbei Parametern mach nur bei Referenzen und Zeigern sinn. Ansonsten wird der übergebene Wert sowieso kopiert.Ich nehme mal an das gilt auch für die Rückgabetypen? Oder ist das const hier unsinnig.
const Object* MyFunc(); const Object& MyFunc();Und sollte man (wie z.B. bei Qt) Getter-funktionen immer als const definieren?
QSize minimumSizeHint() const; int heightForWidth(int) const;Hier würde ich beide Methoden const machen. Die Entscheidung, ob eine Methode const ist, sollte nicht davon abhängen, ob die Methode etwas verändert, sondern ob es ein logisches const ausdrückt.
-
StellerFragen schrieb:
Kannst du das nochmal etwas genauer erklären? Wieso sind hier nach außen Implementierungsdetails sichtbar?
void func(const double, const double);Weil es dem Aufrufer der Funktion völlig egal sein kann, was du mit deinen Kopien machst.
shadow schrieb:
Welche kluge Kopf sagte das nochmal? "Optimiere erst, wenn es wirklich erforderlich ist. Optimierungen während der Implementation machen wenig Sinn und verkomplizieren die eigentlich simple Lösung."
Den Satz halte ich persönlich für unsinnig. Wieso sollte ich mir die Arbeit machen im Nachhinein den Code nochmal optimieren zu müssen. Man ist dann teilweise nicht mehr im Thema drin, muss sich neu einarbeiten. Und jeder, der schonmal in seinem Projekt nachträglich mit const hantiert hat, wird die Erfahrung gamacht haben, dass plötzlich an 100 anderen Stellen ebenfalls const nötig wurde. Ich will aus Prinzip immer die optimale Lösung auch wenn es keinen wirklichen Performancevorteil verspricht ;).
So denken alle Programmierer am Anfang. Und später mit mehr Erfahrung sagen sie dann, dass die Warnungen gegen die frühzeitige Optimierung vollkommen berechtigt sind. Tja, irgendwie wirken diese Warnungen nicht, anscheinend muss jeder erst einmal selbst diese Erfahrungen machen.
EOutOfResources_At_Work schrieb:
Besser:
constbei Parametern mach nur bei Referenzen und Zeigern sinn. Ansonsten wird der übergebene Wert sowieso kopiert.Ich nehme mal an das gilt auch für die Rückgabetypen? Oder ist das const hier unsinnig.
const Object* MyFunc(); const Object& MyFunc();Diese consts sind nicht unsinnig und machen einen echten Unterschied, wie man die Funktion benutzen kann.
Und sollte man (wie z.B. bei Qt) Getter-funktionen immer als const definieren?
QSize minimumSizeHint() const; int heightForWidth(int) const;Das nenn man const-correctness. Das fällt unter:
SeppJ schrieb:
[const] ist ein Werkzeug, um besser entwickeln zu können und damit schon viele Fehler beim Compilieren zu entdecken, die man ansonsten später mühselig mit dem Debugger suchen müsste.
-
Ok, so langsam wirds klarer.
const Object* MyFunc(); const Object& MyFunc();Diese consts sind nicht unsinnig und machen einen echten Unterschied, wie man die Funktion benutzen kann.
Ah, mein Fehler. Ich dachte die const beziehen sich auf die Zeiger. Stattdessen aber auf das Object. Was ich eigentlich meinte war
Object* const MyFunc(); Object& const MyFunc();Das sollte nun aber unsinnig sein?
-
StellerFragen schrieb:
Object* const MyFunc(); Object& const MyFunc();Das sollte nun aber unsinnig sein?
Das erste ist unsinnig, das zweite ill-formed. Das const in
Object* const MyFunc();wird vom Compiler nicht ignoriert, man muss es also in allen Deklarationen angeben. Der Typ eines Funktionsaufrufes ist trotzdem nur Object* (und somit hat const keinen Einfluss auf die Semantik des Aufrufs und ist folglich völlig überflüssig).
rvalues (prvalues) sind niemals cv-qualifiziert es sei denn, es handelt sich um Klassenobjekte: und das ist auch der Grund; nur wenn es sich um eine Klasse handelt, ist ein rvalue überhaupt ein Objekt, so dass const/volatile eine Rolle spielen kann.
-
StellerFragen schrieb:
Ah, mein Fehler. Ich dachte die const beziehen sich auf die Zeiger. Stattdessen aber auf das Object. Was ich eigentlich meinte war
Object* const MyFunc(); Object& const MyFunc();Das sollte nun aber unsinnig sein?
Ja. Dein Compiler sollte dich auch irgendwie davor warnen (zumindest mit ein paar strengeren Warnungsoptionen), weil davon auszugehen ist, dass du das anders meintest.
edit: Und das zweite ist sogar illegal, siehe campers Beitrag.
-
SeppJ schrieb:
shadow schrieb:
Welche kluge Kopf sagte das nochmal? "Optimiere erst, wenn es wirklich erforderlich ist. Optimierungen während der Implementation machen wenig Sinn und verkomplizieren die eigentlich simple Lösung."
Den Satz halte ich persönlich für unsinnig. Wieso sollte ich mir die Arbeit machen im Nachhinein den Code nochmal optimieren zu müssen. Man ist dann teilweise nicht mehr im Thema drin, muss sich neu einarbeiten. Und jeder, der schonmal in seinem Projekt nachträglich mit const hantiert hat, wird die Erfahrung gamacht haben, dass plötzlich an 100 anderen Stellen ebenfalls const nötig wurde. Ich will aus Prinzip immer die optimale Lösung auch wenn es keinen wirklichen Performancevorteil verspricht ;).
So denken alle Programmierer am Anfang. Und später mit mehr Erfahrung sagen sie dann, dass die Warnungen gegen die frühzeitige Optimierung vollkommen berechtigt sind. Tja, irgendwie wirken diese Warnungen nicht, anscheinend muss jeder erst einmal selbst diese Erfahrungen machen.
Naja, ich denke es ist wichtig dazuzusagen von was für einer Art Optimierung man da redet. Das gemeinte Zitat von Don Knuth ("premature optimization is the root of all evil") bezieht sich im Originalkontext auf Mikrooptimierungen. Also z.B. sowas wie eine in ASM handgecodete Wurzelfunktion. Und was das angeht stimmt das natürlich. Denn mein sqrt() kann ich später problemlos durch eine schnellere Funktion ersetzen, sofern das notwendig werden sollte. Allerdings fängt Optimierung schon im high-level Design einer Software an. Das berühmte Zitat stammt aus einer Zeit lange bevor man irgendwie über sowas wie Softwaredesign nachgedacht hat. Ich würde sogar soweit gehen und behaupten dass das ein sehr viel wesentlicherer performancebestimmender Faktor sein kann. Denn wenn das grundlegende Design ineffizient ist kann ich später evtl. gar nichtmehr wirklich optimieren. Hier und da ein paar Cycles rausquetschen macht nicht den Unterschied. Und daran später was zu ändern ist bestenfalls viel Arbeit. Ich denke vor allem erfahrenere Programmierer denken grundsätzlich sehr viel über Performance nach, wenn auch auf anderer Ebene...
-
Und fällt diese Frage deiner Meinung nach nicht unter Mikrooptimierung?
Und ich denke Herr Knuth hat das auch nicht unbedingt so gemeint, wie du denkst. Nach der 80-20 Regel kann ich mir durchaus erlauben, erst einmal schnell zu entwickeln und nicht auf die Laufzeit zu achten. Mit dieser Vorgehensweise habe ich dann in 80% des Codes Recht. Und die letzten 20% sind leicht zu finden und dann kann ich optimieren.
Und ja, das habe ich früher auch anders gesehen. Und mit mehr Erfahrung sage ich nun auch, dass ich damit unrecht hatte und mir viel unnötige Arbeit hätte sparen können. Aber auf die alten Knacker wollte ich damals auch nicht hören, was könnten die mir schon sagen?

-
StellerFragen schrieb:
Ah, mein Fehler. Ich dachte die const beziehen sich auf die Zeiger. Stattdessen aber auf das Object. Was ich eigentlich meinte war
Ein Grund warum ich mir die alternative Schreib- und Sprechweise inzwischen angewöhnt habe:
const int * a; // \ Identisch, bezieht sich auf den "int"-Anteil int const * b; // / [<- Ziehe ich vor] int * const c; // Bezieht sich auf den Zeigeranteil const int * const d; // \ Identisch, sowohl auf "int" wie Zeiger bezogen. int const * const d; // / [<- Ziehe ich vor]Ich schreibe const einheitlich hinter den Teil der konstant ist, mit der Sprechweise "int-Konstante Zeiger-Konstante". Referenzen, da nur Aliasnamen, können (wie schon erwähnt) nicht const deklariert werden.
Grundsätzlich macht const nur da Sinn, wo es einen Mehrwert an Informationen liefert. Wenn du etwas als Kopie übergibst, hat es keinen Mehrwert für den Aufrufenden ob du die Kopie änderst oder nicht, nur wenn du den Übergabewert auch für den Aufrufer potentiell ändern kannst (Referenz/Zeiger) hat dies Informationscharakter.
Ebenso hat es ein Informationscharakter, wenn du besagst das eine Methode nichts an den inneren Werten des Objektes ändert.
Bei der Rückgabe kommt es auf die Zielsetzung an. Wobei ich bei der Rückgabe von "nackten" Zeigern oder Referenzen immer etwas vorsichtiger werde, nicht weil es zwangsweise unsinnig ist, sondern weil es potentiell ein Fehler sein könnte. Bei einem Zeiger als Rückgabe frage ich mich in dem ersten Moment immer, wer diesen Zeiger verwaltet (Allokation/Freigabe), bei Referenzen bin ich vorsichtig, da ich schon sehr häufig den Anfängerfehler gesehen habe das jemand lokale Variablen per Referenz zurück geben will - die aber ihre Gültigkeit verlieren.
-
SeppJ schrieb:
Und fällt diese Frage deiner Meinung nach nicht unter Mikrooptimierung?
Natürlich, die konkrete Frage im Anfangspost hier fällt darunter. Allerdings hatte ich den Eindruck dass die Diskussion über Premature Optimization hier eher genereller Natur ist.
SeppJ schrieb:
Und ich denke Herr Knuth hat das auch nicht unbedingt so gemeint, wie du denkst. Nach der 80-20 Regel kann ich mir durchaus erlauben, erst einmal schnell zu entwickeln und nicht auf die Laufzeit zu achten. Mit dieser Vorgehensweise habe ich dann in 80% des Codes Recht. Und die letzten 20% sind leicht zu finden und dann kann ich optimieren.
Herr Knuth hat das vor allem in einer Zeit (1974) gesagt wo man über sowas wie "Softwaredesign" wohl nichtmal ansatzweise nachgedacht hat

Die 20% zu finden mag kein Problem sein. Aber wenn diese 20% sich ums Dispatchen von irgendwelchen hochabstrakten Calls kümmern, weil das Design einfach nur furchtbar overengineered ist, wirds mit dem einfach mal diese 20% optimieren schwer. Denn eine Änderung an diesen 20% wirkt sich dann auf weit mehr als 20% des Codes aus.EDIT: Nur um dem vorzubeugen: Ich sage nicht dass virtuelle Funktionen langsam und schlecht sind.
EDIT2: Um es vielleicht nochmals anders zu sagen: Ob 80% der Zeit in 20% des Codes verbracht werden und ob ich die betroffenen 20% einfach so optimieren kann, sind zwei völlig verschiedene Dinge. Denn diese 20% des Codes existieren nicht in völliger Isolation von den restlichen 80% des Codes. Wenn ich das System nicht von vornherein schon so gebaut habe dass ich nun die notwendigen Optimierungen an den 20% vornehmen kann, dann werden zur Optimierung der 20% evtl. tiefgreifende Änderungen am System notwendig. Und wenn ich das System so bauen will dass ich die 20% optimieren kann, muss ich mir schon beim Entwerfen des System zumindest grob darüber im Klaren sein was für Optimierungen ich vielleicht einmal vornehmen will. D.h. ich muss mir beim Design schon aktiv Gedanken über Optimierungen machen, auch wenn ich diese vielleicht nie tatsächlich implementiere. Das ist alles was ich mit meinem letzten Posting sagen wolle

-
camper schrieb:
hustbaer schrieb:
Globales Zeugs (auch static in Klassen/Funktionen) mit integralem Typ kann mit const als Comiletime-Konstante behandelt werden, ohne const nicht.
Was genau hat das mit Optimieren zu tun?
Viel?
Es macht für den Code-Generator/Optimizer oft nen Unterschied ob ein Ausdruck compiletime-konstant ist (bzw. so behandelt werden kann), oder nicht.
Beispiel:
#include <iostream> static int foo = 10; static const int cfoo = 10; int main() { std::cout << static_cast<void*>(&foo) << std::endl; std::cout << static_cast<void*>(&cfoo) << std::endl; srand(time(0)); int v = rand(); std::cout << v / foo << std::endl; // div std::cout << v / cfoo << std::endl; // mul }