Es scheint mir, dass es perfekt funktionieren würde, eine Tail-Rekursionsoptimierung sowohl in C als auch in C ++ durchzuführen, aber beim Debuggen sehe ich nie einen Frame-Stack, der diese Optimierung anzeigt. Das ist irgendwie gut, denn der Stapel sagt mir, wie tief die Rekursion ist. Die Optimierung wäre aber auch nett.
Führen C ++ - Compiler diese Optimierung durch? Warum? Warum nicht?
Wie kann ich dem Compiler sagen, dass er es tun soll?
- Für MSVC:
/O2
oder/Ox
- Für GCC:
-O2
oder-O3
Wie wäre es zu überprüfen, ob der Compiler dies in einem bestimmten Fall getan hat?
- Aktivieren Sie für MSVC die PDB-Ausgabe, um den Code verfolgen zu können, und überprüfen Sie dann den Code
- Für GCC ..?
Ich würde immer noch Vorschläge machen, wie ich feststellen kann, ob eine bestimmte Funktion vom Compiler so optimiert wird (obwohl ich es beruhigend finde, dass Konrad mir sagt, ich solle sie annehmen).
Es ist immer möglich zu überprüfen, ob der Compiler dies überhaupt tut, indem er eine Endlosrekursion durchführt und prüft, ob dies zu einer Endlosschleife oder einem Stapelüberlauf führt (ich habe dies mit GCC gemacht und herausgefunden, dass dies -O2
ausreichend ist), aber ich möchte es sein in der Lage, eine bestimmte Funktion zu überprüfen, von der ich weiß, dass sie trotzdem beendet wird. Ich würde gerne eine einfache Möglichkeit haben, dies zu überprüfen :)
Nach einigen Tests stellte ich fest, dass Destruktoren die Möglichkeit dieser Optimierung ruinieren. Manchmal kann es sich lohnen, den Gültigkeitsbereich bestimmter Variablen und Provisorien zu ändern, um sicherzustellen, dass sie außerhalb des Gültigkeitsbereichs liegen, bevor die return-Anweisung beginnt.
Wenn nach dem Tail-Call ein Destruktor ausgeführt werden muss, kann die Tail-Call-Optimierung nicht durchgeführt werden.
quelle
gcc
hat eine engere Option,-foptimize-sibling-calls
um "rekursive Geschwister- und Schwanzaufrufe zu optimieren". Diese Option (nachgcc(1)
Handbuchseite für die Versionen 4.4, 4.7 und 4.8 Targeting verschiedene Plattformen) auf Ebenen aktiviert-O2
,-O3
,-Os
.gcc 4.3.2 fügt diese Funktion (beschissene / triviale
atoi()
Implementierung) vollständig einmain()
. Optimierungsstufe ist-O1
. Ich merke, wenn ich damit herumspiele (selbst wenn ich es vonstatic
aufextern
ändere, verschwindet die Schwanzrekursion ziemlich schnell, sodass ich mich bei der Programmkorrektheit nicht darauf verlassen würde.quelle
extern
Methode inline sein könnte.-O1
gibt es kein inlining und keine Schwanz-Rekursion Optimierung . Sie müssen verwenden-O2
dafür (na ja, in 4.2.x, die nun eher alte ist, wird es noch nicht inline sein). Übrigens: Es ist auch erwähnenswert, dass gcc die Rekursion optimieren kann, auch wenn es sich nicht ausschließlich um eine Endrekursion handelt (wie bei einem faktoriellen Akku ohne Akkumulator).Neben dem Offensichtlichen (Compiler führen diese Art der Optimierung nur durch, wenn Sie danach fragen) ist die Tail-Call-Optimierung in C ++ komplex: Destruktoren.
Gegeben etwas wie:
Der Compiler kann dies (im Allgemeinen) nicht durch Tail-Call optimieren, da er den Destruktor von aufrufen muss,
cls
nachdem der rekursive Aufruf zurückgegeben wurde.Manchmal kann der Compiler feststellen, dass der Destruktor keine von außen sichtbaren Nebenwirkungen hat (dies kann also frühzeitig erfolgen), aber oft nicht.
Eine besonders häufige Form davon ist, wo
Funky
tatsächlich einestd::vector
oder eine ähnliche ist.quelle
Die meisten Compiler führen in einem Debug-Build keine Optimierung durch.
Wenn Sie VC verwenden, versuchen Sie es mit einem Release-Build mit aktivierten PDB-Informationen. Auf diese Weise können Sie die optimierte App nachverfolgen und sollten hoffentlich sehen, was Sie dann möchten. Beachten Sie jedoch, dass Sie durch das Debuggen und Verfolgen eines optimierten Builds überall herumspringen und Variablen häufig nicht direkt untersuchen können, da sie immer nur in Registern landen oder vollständig optimiert werden. Es ist eine "interessante" Erfahrung ...
quelle
Wie Greg erwähnt, werden Compiler dies im Debug-Modus nicht tun. Es ist in Ordnung, dass Debug-Builds langsamer sind als ein Prod-Build, aber sie sollten nicht öfter abstürzen. Wenn Sie auf eine Tail-Call-Optimierung angewiesen sind, können sie genau das tun. Aus diesem Grund ist es oft am besten, den Tail-Aufruf als normale Schleife umzuschreiben. :-(
quelle