std::stack / Wieso keine clear Methode?



  • Dravere schrieb:

    @BarnieGeroellheimer,
    Ich will ja kein Objekt dazwischen wegenehmen, ich will den ganzen Stack leeren, ALLES! Mir egal, ob er dann automatisch eines nach dem anderen von oben weg nimmt oder nicht, das ist ja scheiss egal. Der Stack muss nachher nur leer sein.
    Und jegliche Container aus der Standard Bibliothek unterstützen ein clear, also wäre das für std::stack kein Problem, noch sowas vorauszusetzen. Es könnte einfach deutlich effizienter ausgeführt werden, bzw. auch eine eindeutige Funktion dafür anbieten.

    Nein, man kann nicht einfach ein clear als Memberfunction anbieten. Das wäre eine Schnittstellenerweiterung. Und Schnittstellen beschreiben, was ein Typ machen kann. Und ein Stack kann nicht "clear" machen. Du solltest nochmal über den Sinn von Memberfunctions nachdenken! 😉

    Wenn du eine Komfort-Funktion suchst (was eigentlich so zu sein scheint!), dann mach sowas:

    void clear(std::stack &s)
    {
         while(!s.empty())
               s.pop();
    }
    

    und leg es in deine Toolbox, wo du von jedem Projekt drauf kommst.



  • Der Grund ist relativ einfach: std::stack kann mit jedem Container benutzt werden der ein paar Voraussetzungen erfüllt:
    http://www.cplusplus.com/reference/stl/stack/

    er muss die methoden back(), push_back() und pop_back() bereitstellen. Jeder Benutzerdefinierte Container (oder wenn wir schon dabei sind auch jeder Container aus einer Fremdbibliothek), der diese drei Methoden anbietet, kann als templateargument für std::stack benutzt werden. Wenn man std::stack jetzt noch mit einem clear() ausstatten wollte müsste man entsprechende Vorgaben an die Container machen und damit die Wiederverwendbarkeit des stack-templates einschränken.
    Wie Boris aber schon ganz richtig festgestellt hat, würde ein clear() bei einem Stack nur selten benutzt - also wäre das eine Enschränkung an die Wiederverwendbarkeit die nur in seltenen Fällen einen kleinen Performance-Vorteil bringen könnte. Kein besonders guter Deal oder?


  • Administrator

    pumuckl schrieb:

    Der Grund ist relativ einfach: std::stack kann mit jedem Container benutzt werden der ein paar Voraussetzungen erfüllt:
    http://www.cplusplus.com/reference/stl/stack/

    Soweit mir bekannt ist, unterstützt jeder Container aus der Standardbibliothek ein clear. Zu den benutzerdefinierten Container später.

    pumuckl schrieb:

    ...
    Wie Boris aber schon ganz richtig festgestellt hat, würde ein clear() bei einem Stack nur selten benutzt - also wäre das eine Enschränkung an die Wiederverwendbarkeit die nur in seltenen Fällen einen kleinen Performance-Vorteil bringen könnte. Kein besonders guter Deal oder?

    Das scheint in erster Linie so zu sein. Aber seien wir mal ehrlich, kennst du einen Container, welcher kein clear aufweist? Bzw. keine Funktion mit dieser Funktionalität? Mir ist ehrlich gesagt keiner bekannt. Es wäre auch ziemlicher Unsinn. Daher sehe ich da keinen schlechten Deal, sondern nur einen Gewinn.

    Und ich verlange ja auch kein insert oder sowas seltsames. Das ist ja auch nicht der Sinn eines Stacks. Aber ein Stack kann geleert werden, das ist eine Eigenschaft eines Stacks. Punkt. Wieso nicht effizient anbieten?

    Grüssli


  • Mod

    std::stack ist doch sowieso die mit Abstand überflüssigste Komponente der Standardbibliothek. Wozu darüber streiten?



  • BarnieGeroellheimer schrieb:

    Noch ein Beispiel:

    void foo()
    {
       int i;
       int t;
    }
    

    i und t liegen auf dem Stack. Wie werden die bei Verlassen von foo weggeräumt? Beide auf einmal? Nein, erst wird t weggeräumt und dann i. Da kannst du dich auf den Kopf stellen, die CPU wird es nicht anders machen, weil der Stack so definiert ist.

    Nein, normalerweise räumt die CPU solche Variablen alle auf einmal weg. Zum Beispiel auf x86 gibt es den Asembler-Befehl "add esp, 8", der beide ints in einem Rutsch vom Stack entfernt. Oder alternativ auch "mov esp, ebp", wenn in ebp der Stackpointer ohne i, j steht.



  • camper schrieb:

    std::stack ist doch sowieso die mit Abstand überflüssigste Komponente der Standardbibliothek. Wozu darüber streiten?

    👍


  • Administrator

    camper schrieb:

    std::stack ist doch sowieso die mit Abstand überflüssigste Komponente der Standardbibliothek. Wozu darüber streiten?

    Wir können es noch erweitern auf std::queue und std::priority_queue , aber irgendwie beschleicht mich das Gefühl, dass du diese auch als überflüssig ansehen wirst 🙂

    Aber wie gesagt, mich würde eigentlich hauptsächlich interessieren, wieso das Standard-Komitee so entschieden hat. Bis jetzt haben eigentlich alle nur irgendwelche Behauptungen aufgestellt, die allerdings meiner Meinung nach alle keinen Boden unter den Füssen haben.

    Grüssli



  • "add esp, 8"

    da wird die CPU trozdem die variablen nacheinander aufräumen nehm ich an oder ist quasie der clear befehl, und clear räumt die elemente auch nacheinder weg^^



  • BorisDieKlinge schrieb:

    "add esp, 8"

    da wird die CPU trozdem die variablen nacheinander aufräumen nehm ich an oder ist quasie der clear befehl, und clear räumt die elemente auch nacheinder weg^^

    Nein, das ist ein arithmetischer Befehl, bekannt als Addition. Den kann die CPU schon in einem Schritt ausführen.



  • Dravere schrieb:

    ...Das mit deinem Beispiel funktioniert leider nicht. Und zwar aus dem Grund, weil man ein Stack auch leeren kann, indem man der Reihe nach alle Elemente vom Stack runternimmt. Und wenn das erst noch effizient geht, über eine zusätzliche Methode, wieso sollte man diese nicht implementieren?...

    Neeee.
    Dein "selbstgebasteltes Stack-Clear" ist strukturell etwas anderes als ein clear() auf den zugrundeliegen Container. Es mag zwar in einigen Implementierungen denselben Effekt haben, aber das bedeutet noch lange nicht, dass es dasselbe sei ... einem stack wäre z.B. durchaus erlaubt, bei pop() lediglich einen "actElement-Zeiger" zu verschieben.

    Nochmal: Bloß weil ein Stack seine Funktionialität intern über einen Container implementiert, bedeutet es noch lange nicht, dass er ein solcher ist.

    Stell Dir "Stack" eher wie ein Design-Pattern vor, das für einen spezifischen Zweck entsprechende Funktionalitäten bietet. Mehr ist nicht seine Aufgabe und es wäre IMHO sogar schlecht, wenn es darüber hinaus implementierungsspezifische Funktionalitäten nach außen weiterleitet.

    Gruß,

    Simon2.


  • Administrator

    Simon2 schrieb:

    Dein "selbstgebasteltes Stack-Clear" ist strukturell etwas anderes als ein clear() auf den zugrundeliegen Container. Es mag zwar in einigen Implementierungen denselben Effekt haben, aber das bedeutet noch lange nicht, dass es dasselbe sei ... einem stack wäre z.B. durchaus erlaubt, bei pop() lediglich einen "actElement-Zeiger" zu verschieben.

    Es kann ja dann auch frei definiert werden, was bei einem clear passiert. Bei einem std::vektor, wird der Speicher auch nicht freigegeben. Das ist dann demjenigen überlassen, welcher den Container schreibt. Ob da ein Zeiger verschoben wird, der Speicher freigegeben wird, oder "blau" auf der Konsole rauskommt, ist völlig egal. std::stack ist ja nur ein Adapter, welcher die Aufrufe direkt an den Container weiterleitet. std::stack selber macht eigentlich gar nichts! Und somit könnte er auch einfach direkt ein clear weiterleiten. Wenn du willst, sogar ein stack_clear oder sowas, wobei ich das allerdings unnötig fände.

    Simon2 schrieb:

    Nochmal: Bloß weil ein Stack seine Funktionialität intern über einen Container implementiert, bedeutet es noch lange nicht, dass er ein solcher ist.

    Das haben ich jetzt schon zigg tausend Male gehört, dabei noch gar nie behauptet!

    Grüssli



  • Dravere schrieb:

    ...
    Es kann ja dann auch frei definiert werden, was bei einem clear passiert. ...

    Klar - aber auch das ist nicht der Punkt, auf den ich hinauswill. Sondern: "Dein Stack-clear" != "<zugrundeliegender-Container>.clear()"
    ... diese Ungleichheit bedeutet, dass Deine Aussage "Ich kann's selbst basteln" nicht stimmt.

    Dravere schrieb:

    ...
    std::stack ist ja nur ein Adapter, welcher die Aufrufe direkt an den Container weiterleitet. ...

    Muss er nicht.
    Hier gehst Du wieder von einer bestimmten Implementation aus und nicht vom zugrundeliegenden Konzept (und "Stack" ist genaugenommen erstmal nur ein Konzept).

    Dravere schrieb:

    ...
    Das haben ich jetzt schon zigg tausend Male gehört, dabei noch gar nie behauptet!...

    Doch - genau das behauptest Du ständig (wenn auch implizit) mit der Frage, warum stack kein "clear()" hat (bzw. der Forderung, es müsse doch eines haben) und mit Deinem "clear-Nachbau-Ansatz".

    Gruß,

    Simon2.



  • clear fehlt weil designfehler. so einfach ist das.



  • Shade Of Mine schrieb:

    clear fehlt weil designfehler. so einfach ist das.

    Denk ich auch. Wäre mal interessant, ob die die behaupten, dass es dafür einen Grund gibt auch eine offizielle Quelle dazu haben.



  • Shade Of Mine schrieb:

    clear fehlt weil designfehler. so einfach ist das.

    Quelle ?

    Gruß,

    Simon2.


  • Administrator

    @Simon2,
    Ich glaube du verstehst da was falsch. Ich sage nur, dass man einen Stack leeren kann. Wieso nicht eine optimierte Methode dafür anbieten?
    Egal was dieses leeren ist, die Eigenschaft besteht.

    Simon2 schrieb:

    Dravere schrieb:

    ...
    std::stack ist ja nur ein Adapter, welcher die Aufrufe direkt an den Container weiterleitet. ...

    Muss er nicht.
    Hier gehst Du wieder von einer bestimmten Implementation aus und nicht vom zugrundeliegenden Konzept (und "Stack" ist genaugenommen erstmal nur ein Konzept).

    Ich weiss nur, dass es in der Dinkumware StdLib so implementiert ist und es macht auch nicht all zu viel anders Sinn. Das Konzept vom Stack besteht darin, dass ein Container genommen wird und zum Beispiel bei top beim zugrunde liegenden Container back() aufruft.
    Wieso also nicht auch ein clear() , welches zu einem clear() vom Container weitergeleitet wird?

    Simon2 schrieb:

    Doch - genau das behauptest Du ständig (wenn auch implizit) mit der Frage, warum stack kein "clear()" hat (bzw. der Forderung, es müsse doch eines haben) und mit Deinem "clear-Nachbau-Ansatz".

    Nein, eben nicht. Ich verlange, dass stack als Konzept das clear unterstützen sollte.

    Stell dir am besten vor, dass std::stack kein top() hätte und ich verlange nun ein top() , da dies ja typisch für einen Stack ist. Es läuft auf das genau gleiche hinaus, einfach top() mit clear() ersetzen.

    @Shade Of Mine,
    So sehe ich das derzeit. Aber ich frage mich halt, ob es wirklich ein Designfehler war, oder ob man es weggelassen hat, aus den gleichen sinnlosen Gründen, wie hier genannt wurden. Oder doch einen sinnvollen Grund?
    Aber eigentlich ist es ja auch egal. Ich find es nur extrem schade.
    Wird das vielleicht im C++0x Standard geändert?

    Grüssli



  • Shade Of Mine schrieb:

    clear fehlt weil designfehler. so einfach ist das.

    oder: "Das clear bei Containern ist ein Designfehler; und beim Stack hat man's gemerkt". Beweis: es gibt einen Destruktor.

    Ich finde clear() bei Containern genauso überflüssig wie close() bei fstream. Letztlich hat immer der Destruktor den Job, hinterher alles aufzuräumen, was noch übrig bleibt.

    Dravere schrieb:

    Aber irgendwann ist die Aufgabe beendet und der Stack ist bei mir dann nicht zwingend leer, muss er auch nicht sein. Wenn die Aufgabe aber wieder von vorne beginnen soll, mit dem gleichen Objekt, dann muss der Stack leer sein. Also brauche ich ein clear, welches mir garantiert, das der Stack leer ist, nach dessen aufruf.

    braucht man eben nicht, wenn die 'Aufgabe' in einem Scope passiert und das 'Arbeitsobjekt' - in diesem Fall der Stack - nicht außerhalb sondern eben innerhalb des Scopes angelegt wird. Das Anlegen eines (leeren) Containers oder Stacks ist im Allgemeinen mit mehr oder weniger keinem Aufwand verbunden. Der Code wird dadurch klarer (Stack existiert nur im Scope) und kürzer (clear unnötig) und robuster, weil mit jedem Verlassen des Scopes im Fehlerfall oder sonstwie (z.B. Exception) wird automatisch aufgeräumt.

    Gruß
    Werner



  • Dravere schrieb:

    ...Das Konzept vom Stack besteht darin, dass ein Container genommen wird und zum Beispiel bei top beim zugrunde liegenden Container back() aufruft....

    Du kannst es gerne noch auf 20 weitere Arten neu schreiben, es wird dadurch nicht richtiger. Du beschreibst eine Implementierungsmöglichkeit von "Stack".
    Aber das "Konzept" von Stack lautet einfach: "Ich kann Dinge sukkzessive drauflegen und wieder herunternehmen".

    Gruß,

    Simon2.



  • Werner Salomon schrieb:

    Shade Of Mine schrieb:

    clear fehlt weil designfehler. so einfach ist das.

    oder: "Das clear bei Containern ist ein Designfehler; und beim Stack hat man's gemerkt". Beweis: es gibt einen Destruktor.

    Ich finde clear() bei Containern genauso überflüssig wie close() bei fstream. Letztlich hat immer der Destruktor den Job, hinterher alles aufzuräumen, was noch übrig bleibt.

    Also nen filestream kannst du wohl nicht mit nem Container vergleichen. Wieso sollte man den nen Container nie leeren müssen? Das ist doch Quatsch, dass ich immer nen neuen erzeugen muss, nur weil ich ihn leeren will. Und es gibt auch Container die länger als nur einen Funktionsaufruf gültig sind. Wenn du z.B. nen Undo und nen Redo Stack hast und den Redo Stack immer dann leeren willst, wenn was neues in den Undo Stack kommt, meinst du dass man dann immer delete und new machen sollte?



  • Werner Salomon schrieb:

    Ich finde clear() bei Containern genauso überflüssig wie close() bei fstream. Letztlich hat immer der Destruktor den Job, hinterher alles aufzuräumen, was noch übrig bleibt.

    clear räumt nicht auf, clear zerstört nur alle objekte. das ist grundverschieden zu einem close() oder dtor...

    deshalb gibt es ja für wirkliches resetten eines containers den swap trick.


Anmelden zum Antworten