Stack-Objekte in while-Schleife und Exceptions



  • Hallo,

    der Vorteil von Stack-Objekten liegt ja darin,
    dass beim Verlassen des Scope die Objekte
    automatisch verworfen werden.
    Jetzt möchte ich zu einem anderen Objekt
    per add mehrere Objekte hinzufügen ohne
    jedoch die Verantwortlichkeit für die Lebensdauer
    dieses Objektes zu übergeben. Per Stack-Objekt
    geht ja nicht, da das gleiche Objekt ich immer
    die gleiche Adresse hat. Also bleibt mir ja nichts
    anderes über als es auf dem Heap zu erzeugen, nur
    dann wird bei ner Exception das Objekt nicht mehr gelöscht.

    Wie macht man sowas am besten?

    Gruß,
    Referencer



  • Hi,

    ein bisschen Code wäre hilfreich...
    Zum Problem: Da du "ReferenceProblem" heißt denke ich das du die Objekte per Referenz übergibts. Übergib sie in deinem Fall per Value.



  • Hallo

    Wenn du z.B. ein std::vector nimmst, kannst du mehrere Stack-Instanzen zusammenfassen ohne dich um deren Freigabe zu kümmern.

    bis bald
    akari



  • Also so geht es ja nicht, da alle Objekte die gleiche Adresse haben...

    ObjectA a = ObjectA();
    for(int i=0; i<6; ++i){
       ObjectB b = ObjectB();
       a.add(b); // void add(ObjectA& a);
    }
    

    So krieg ich Probleme mit der Freigabe, falls irgendwo ne Exception fliegt:

    ObjectA a = ObjectA();
    for(int i=0; i<6; ++i){
       ObjectB* b = new ObjectB();
       a.add(*b);
    }
    


  • Im 2. Fall natürlich immer 🙂
    nicht nur bei ner Exception...



  • im ersten beispiel haben die objekte nicht immer dieselbe adresse. es kann passieren, ist aber nicht garantiert.

    und so wie dein problem klingt, wärs vielleicht sinnvoll einfach mit kopien (by value, wie von freak_coder schon vorgeschlagen) zu arbeiten.

    void add(Object o);
    


  • Dann krieg ich aber Probleme mit pure virtual...

    Oder liegt in diesem Fall schlechtes Design vor?

    thordk schrieb:

    im ersten beispiel haben die objekte nicht immer dieselbe adresse. es kann passieren, ist aber nicht garantiert.

    Gibt es ne Regel, wann es so ist und wann nicht?



  • ReferenceProblem schrieb:

    Gibt es ne Regel, wann es so ist und wann nicht?

    nicht dass ich wüsste.

    das lokale objekt wird bei verlassen des scope zerstört. das geschieht bei jedem schleifendurchlauf. beim nächsten aufruf wird sie wieder angelegt. dabei könnte sie u.u. an derselben stelle im speicher angelegt werden und vielleicht macht nen compiler das auch so beim optimieren. aber garantiert ist da nix.



  • thordk schrieb:

    ReferenceProblem schrieb:

    Gibt es ne Regel, wann es so ist und wann nicht?

    nicht dass ich wüsste.

    das lokale objekt wird bei verlassen des scope zerstört. das geschieht bei jedem schleifendurchlauf. beim nächsten aufruf wird sie wieder angelegt. dabei könnte sie u.u. an derselben stelle im speicher angelegt werden und vielleicht macht nen compiler das auch so beim optimieren. aber garantiert ist da nix.

    Probier einfach nen kleines Beispielprogramm zu basteln wo die Adresse NICHT gleich ist. Würde mich wundern wenn das recht einfach geht 😉
    Garantie gibts trotzdem keine, d.h. man sollte sich auch nicht drauf verlassen.

    Und es ist ziemlich wurscht in dem Fall, da es auch nix helfen würde wenn sich die Adresse jedes mal ändert -- wenn die Schleife bei Durchlauf 10 ist sind die 9 Objekte die davor "dort gelebt haben" schon längst zerstört und deine collection hält 9 dangling pointers. Solange diese dangling pointers nicht dereferenziert oder rumgereicht oder sonstwie "angegriffen" werden ist das OK, bloss dann wäre die ganze collection fürn Hugo.

    @ReferenceProblem:

    Ein paar Ansätze:
    * Du könntest shared ownership verwenden (z.b. mit boost::shared_ptr)
    * Du könntest (member) function pointer statt virtual pure verwenden
    * Du könntest nen Guard verwenden



  • Hallo hustbaer,

    ich mach mir mal Gedanken über deine Vorschläge...
    Allerdings kann ich mit

    hustbaer schrieb:

    * Du könntest nen Guard verwenden

    garnichts anfangen.
    Ich kenn nur Include-Guards und mit der Suche bin ich auch nicht
    fündig geworden

    Kann mir jemand erklären, was ein Guard ist?



  • thordk schrieb:

    ...

    void add(Object o);
    

    ReferenceProblem schrieb:

    Dann krieg ich aber Probleme mit pure virtual...

    Kannst Du das mal kurz erklären ?
    Mir fällt so spontan kein Fall ein, wo das zusammenfallen könnte ...

    Außerdem ist mir nicht klar, was Deine Klasse in der Memberfunktion mit der Referenz macht ....

    Gruß,

    Simon2.



  • Vielleicht steh ich aufm Schlauch, aber
    bei nem einfachen Listener ist das doch so...

    Denn bei pure virual hast du ja keinen verwendbaren Copy-Konstruktor



  • ReferenceProblem schrieb:

    ...hast du ja keinen verwendbaren Copy-Konstruktor

    Ach so - Deine Klasse hat keinen CopyCtor. 💡

    Das hatte ich nicht mit "pure virtual" verbunden (dachte da eher an einzelne Memberfunktionen) ....

    Aber so stimmt das natürlich.

    Danke,

    Simon2.



  • Ein Guard ist ne (mehr oder weniger) kleine Hilfsklasse die dafür sorgt dass gewisse Dinge immer gemacht werden/nicht gemacht werden können.
    z.B. könntest du dir eine Guard Klasse programmieren der du Zeiger auf deine Instanzen übergibst, und die dann ownership übernimmt. Weiters teilst du dieser Guard Klasse mit welcher anderen Collection du diese Zeiger übergibst, damit die Guard Klasse vor dem löschen der Objekte diese auch wieder aus der Collection entfernen kann.

    Pseudocode:

    class Guard
    {
        Guard(Collection& c)
            : m_collection(c)
        {
        }
    
        ~Guard()
        {
            for all Objects o in m_objects
            {
                m_collection.Remove(o);
                delete o;
            }
        }
    
        void AddLocalToCollection(Object* o)
        {
            m_objects.push_back(o);
            m_collection.Add(o);
        }
    
        Collection& m_collection;
        vector<Object*> m_objects;
    }
    

    So inetwa



  • Hallo HustBaer...

    Vielen Dank für die ausführliche Erklärung!!!

    Eigentlich ganz easy 😉



  • Argh!
    AddLocalToCollection ist ein scheiss Name, da ist mir wohl noch dein "Stack Objekte" im Kopf rumgeschwirrt - is ja aber nicht "local" sondern "ge-newt" (schönes Wort 😃 ). Sollte vielleicht besser einfach nur Add oder AddAndTakeOwnership heissen.

    Und die Sequenz "push_back" + "Add" ist nicht exception-safe, ist so vielleicht besser:

    class Guard
    {
        Guard(Collection& c)
            : m_collection(c)
        {
        }
    
        ~Guard()
        {
            for all Objects o in m_objects
            {
                if (o)
                {
                    m_collection.Remove(o);
                    delete o;
                }
            }
        }
    
        void AddAndTakeOwnership(Object* p)
        {
            auto_ptr<Object> guard(p); // damit o in jedem Fall gelöscht wird
    
            m_objects.push_back(0);
            m_collection.Add(p);
    
            // jetzt kann nixe mehr schiefgehen
            guard.release();
            m_objects.back() = p;
        }
    
        Collection& m_collection;
        vector<Object*> m_objects;
    }
    

    Is etwas gefrickelt, dafür aber jetzt exception safe 🙂



  • hustbaer schrieb:

    ...aber jetzt exception safe 🙂

    Dazu noch eine Bemerkung @ReferenceProblem: Du solltest Dir auch überlegen, was der Aufrufer Deiner Funktion erwarten soll, wenn er eine Exception "zurückbekommt" ... welchen Zustand hat dann der Container ? Welchen die betroffene(n) Klasse(n) ?
    Das klingt erstmal trivial, aber wenn man sich das genauer ansieht, entwickelt sich eine größere Herausforderung....

    Gruß,

    Simon2.


Anmelden zum Antworten