Stack-Größenproblem umgehen
-
Ich hab gelesen, dass der Stack in C++ begrenzt ist. Stimmt das? Wenn ja, wieso macht man nicht einfach sowas hier:
class Global { int Main() { // Hier kommt alles rein, was sonst in die main kommt, z.B. int x = 5; cout << x; return 0; } }; int main() { Global *global = new Global(); int returnValue = global->Main(); delete global; return returnValue; }Dann hätte man alles (z.B. die Variable x) auf dem Heap, kann die Variablen aber trotzdem so deklarieren, als wären sie auf dem Stack, ohne sich Sorgen zu machen, dass der Stack überläuft und ohne new und delete nur deshalb zu benutzen, weil sonst der Stack überlaufen könnte.
-
Der Stack ist schneller als der Heap.
-
Der Stack ist groß genug und dein Vorgehen vollkommen überflüssig. Bei Rekursionen kann es vorkommen, dass der Stack voll ist, aber ansonsten gibt es dort keine Probleme.
-
Stack-enpferd schrieb:
Ich hab gelesen, dass der Stack in C++ begrenzt ist. Stimmt das?
Natürlich. Auch der Heap/Freestore ist begrenzt.
Stack-enpferd schrieb:
Wenn ja, wieso macht man nicht einfach sowas hier
Weil es nichts bringt. Die Variable
xbefindet sich nicht auf dem Heap. Memberfunktionen werden nicht auf dem Heap angelegt.Und das "Problem" der begrenzten Stackgrösse ist nicht so allgegenwärtig, wie du vielleicht meinst. Sehr oft benutzen Klassen, die grössere Speichermengen benötigen, von selbst dynamischen Speicher – z.B. STL-Container. Und ansonsten forderst du grosse Objekte eben dynamisch an, am besten mit RAII.
Die Stackgrösse wird eher kritisch, wenn du sehr tiefe Rekursionen von Funktionsaufrufen hast.
-
Vielleicht noch eine Bemerkung am Rande:
Auch wenn es tiefe Rekursionen gibt, kann man, wenn die Gefahr eines Stack-Overflow gegeben ist, Die Größe des Stacks bei den Linker-Optionen Anpassen. Der Hauptgrund, dass der Stackspeicher auf 1 MB begrenzt ist der, dass Endlosrekursionen abgebrochen werden.MfG, Jochen
-
Das stimmt zwar, aber das Problem, dass tiefe Rekursionen gefährlich sind, bleibt weiterhin. Zumal es im C++-Standard keine Linkeroptionen gibt und man sich nicht auf solche Einstellungen verlassen sollte, falls man portabel programmieren möchte.
Davon abgesehen verlagert sich das Problem oft nur. Wenn man auf die Idee kommen sollte, im Destruktor einer verketteten Liste rekursiv andere Destruktoren aufzurufen, darf man bei 2MB nun eben mehr Elemente anhängen, bis das Programm abstürzt. Keine besonders gute Lösung. Bei Algorithmen wie Baumdurchsuchungen mit O(log n) stellt sich das Problem hingegen auch bei 1MB Stack nicht, und man gewinnt wieder nichts durch die Stackvergrösserung.
Die Situationen, wo man tatsächlich einen grösseren Stack benötigt, sind recht selten. Oft kann man durch bessere Programmierung mehr bewirken. Nicht zuletzt sollte man auch Datenstrukturen wie
std::stackin Erwägung ziehen, um gefährliche Rekursionen zu umgehen.
-
Rekursionen sind nicht gefährlich, nur der Stack-Overflow. Sofern man weiß, dass der Algorithmus nicht in einen Stack-Overflow laufen kann ist alles bestens.
Und Rekursionen sind meist übersichtlicher und schneller programmiert.
-
einint schrieb:
Rekursionen sind nicht gefährlich, nur der Stack-Overflow. Sofern man weiß, dass der Algorithmus nicht in einen Stack-Overflow laufen kann ist alles bestens.
Tiefe, nicht gut voraussehbare Rekursionen sind gerade wegen des Stack-Overflows potenziell gefährlich. Natürlich nicht alle Rekursionen, ich habe ja selbst ein Gegenbeispiel gebracht.
einint schrieb:
Und Rekursionen sind meist übersichtlicher und schneller programmiert.
Was aber nicht heisst, dass sie generell vorzuziehen sind. Aber falscher Einsatz von Rekursionen zum Glück keines der Verbrechen, das in C++ allzu oft begangen wird (zumindest verglichen mit gewissen anderen Dingen).

-
Rekursion ist oft nicht wirklich die besste Lösung. Die eleganteste, einfachste, logischere ja, aber (und darauf kommt es halt bei vielen Algorithmen an) oftmals langsamer, als die iterative Variante.
Einen hybriden Ansatz, wie bei gewissen Implementierungen von Quicksort ist manchmal aber auch schon ganz passabel.