Kann ein Compiler abhängig vom case-Zweig pushen bzw. konstruieren?
-
@Bashar: Bist du dir sicher, dass ein Objekt in einem Case-Zweig konstruiert wird, obwohl der Zweig nicht erreicht wird? Stackfrager hat doch schon extra einen neuen Block durch seine geschweiften Klammern angefangen. Was sollte den Compiler daran hindern, in den INIT-Case-Zweig einen Konstruktor- und einen Destruktoraufruf einzubauen?
Außerdem glaube ich auch nicht, dass schon am Anfang der Funktion der Stack-Pointer erhöht wird, weil der Compiler gar nicht weiß, wie viel Stack benötigt wird. Außerdem würde bei std::vector sowieso nicht viel Stack benötigt, da er seinen Speicher auf dem Heap anlegt.
-
wxSkip schrieb:
@Bashar: Bist du dir sicher, dass ein Objekt in einem Case-Zweig konstruiert wird, obwohl der Zweig nicht erreicht wird? Stackfrager hat doch schon extra einen neuen Block durch seine geschweiften Klammern angefangen. Was sollte den Compiler daran hindern, in den INIT-Case-Zweig einen Konstruktor- und einen Destruktoraufruf einzubauen?
Bei int gibt es ja nix aufzurufen. Und Konstruktor und Destruktoraufrufe werden natürlich verzögert durchgeführt (wenn es Vorteile bringt), die Stackallocation ist aber völlig unabhängig vom Konstruktoraufruf. Der Konstruktor bekommt bloß eine Speicherstelle mitgeteilt, auf der er arbeiten soll, wann die allokiert wurde ist Wurscht.
Außerdem glaube ich auch nicht, dass schon am Anfang der Funktion der Stack-Pointer erhöht wird, weil der Compiler gar nicht weiß, wie viel Stack benötigt wird. Außerdem würde bei std::vector sowieso nicht viel Stack benötigt, da er seinen Speicher auf dem Heap anlegt.
Er kann sich doch alle Scopes zusammenzählen und dann am Anfang einer Funktion alle Variablen zusammen auf den Stack legen. Es müssen ja nicht alle Variablen benutzt werden. Es muss auch nicht jeder Bereich auf dem Stack ständig der gleichen Variablen entsprechen. Oder eine Variable braucht gar nicht auf dem Stack zu liegen. Da besteht ungeheuer viel Optimierungspotential, dass sich der Compiler bestimmt nicht wegen ein paar Klammern mit rein syntaktischer Funktion wird nehmen lassen.
-
SeppJ schrieb:
Er kann sich doch alle Scopes zusammenzählen und dann am Anfang einer Funktion alle Variablen zusammen auf den Stack legen.
Nicht zusammenzählen. Der Stackbedarf des Funktionsscopes + der größte Stackbedarf der Subscopes reicht ja. In dem Beispiel eben der Speicher für ein int (plus ABI-Interna).
-
wxSkip schrieb:
@Bashar: Bist du dir sicher, dass ein Objekt in einem Case-Zweig konstruiert wird, obwohl der Zweig nicht erreicht wird?
Nein, sorry, ich hab nicht richtig gelesen. (Ich war in Gedanken noch bei der ersten Frage.)
Das Objekt wird nur konstruiert, wenn der Zweig durchlaufen wird.
-
Danke für alle Antworten.
rüdiger schrieb:
Der Stackbedarf des Funktionsscopes + der größte Stackbedarf der Subscopes reicht ja. In dem Beispiel eben der Speicher für ein int (plus ABI-Interna).
Ich denke mal, dass der Compiler zusätzlich ein mögliches "Durchfallen" in den nächsten Zweig entsprechend beachtet.
Dass die maximal anzunehmende Größe verwendet wird, ist im Grunde auch das Naheliegenste - danke für die superschnelle Klärung.
-
Stackfrager schrieb:
D
rüdiger schrieb:
Der Stackbedarf des Funktionsscopes + der größte Stackbedarf der Subscopes reicht ja. In dem Beispiel eben der Speicher für ein int (plus ABI-Interna).
Ich denke mal, dass der Compiler zusätzlich ein mögliches "Durchfallen" in den nächsten Zweig entsprechend beachtet.
Er muss nur die Scopes beachten. Ob das in einem switch/case ist, ist ja egal.
-
manchmal legen compiler die objekte schon vorher an, wenn sie "wissen", dass es keine seiteneffekte hat (z.b. wenn alle member einfach nur auf 0 gesetzt werden muessen), was aergerlich ist wenn man einen grossen switch block hat, bei dem nur ein bruchteil davon benutzt wird, da durch die initialisierung all der variablen schon viel zeit verstreicht.
Einziger work around fuer mich war eine externe funktion im case aufzurufen und dafuer zu sorgen, dass sie nicht geinlined wird. leider kostet der call dann auch etwas.
-
rapso schrieb:
manchmal legen compiler die objekte schon vorher an, wenn sie "wissen", dass es keine seiteneffekte hat (z.b. wenn alle member einfach nur auf 0 gesetzt werden muessen), was aergerlich ist wenn man einen grossen switch block hat, bei dem nur ein bruchteil davon benutzt wird, da durch die initialisierung all der variablen schon viel zeit verstreicht.
Einziger work around fuer mich war eine externe funktion im case aufzurufen und dafuer zu sorgen, dass sie nicht geinlined wird. leider kostet der call dann auch etwas.Ich habe mal gehört, dass Compiler über die Möglichkeit verfügen einzelne Optimierungen gezielt auszuschalten.
-
Um deutlich zu machen: ein Konstruktor wird erst dann aufgerufen, wenn er benötigt wird. Habe ich einen Scope, der nicht durchlaufen wird, wird auch kein Konstruktor aufgerufen. Da gibt es nichts zu deuten. Das heißt auch nicht, dass der Konstruktor verzögert aufgerufen wird. Er wird einfach dann aufgerufen, wenn die Variable angelegt wird.
Ein durch fallen in den nächsten case ist hier nicht relevant, da in einem case keine Variablen ohne eine Scope-Klammer definiert werden dürfen.
Mit dem Stack ist das anders. Der wird gleich am Anfang alloziiert. Aber wie einer schon gesagt hat - das ist bloß eine Addition.
-
ich bins schrieb:
Um deutlich zu machen: ein Konstruktor wird erst dann aufgerufen, wenn er benötigt wird. Habe ich einen Scope, der nicht durchlaufen wird, wird auch kein Konstruktor aufgerufen. Da gibt es nichts zu deuten. Das heißt auch nicht, dass der Konstruktor verzögert aufgerufen wird. Er wird einfach dann aufgerufen, wenn die Variable angelegt wird.
Grundsätzlich ja.
Der Compiler kann aber Code generieren der bestimmte Dinge macht, obwohl das Programm den entsprechenden Zweig gar nicht ausführt. Nämlich dann, wenn die Folgen nicht beobachtbar sind.Also z.B. in genau so einem Fall wie rapso geschildert hat.
Relevant ist das aber nur dann, wenn es um Geschwindigkeit geht, da das beobachtbare Verhalten des Programms sich dadurch ja per Definition nicht verändern kann (darf).