Klassen-Pointer zuweisen/kopieren



  • ich habe eine Klasse foo, die eine unbekannte Anzahl(<=20) an Instanzen der Klasse bar speichern soll, die durch einen Parser erstellt werden.
    Also ca. so:

    class foo{
    bar *barElem[20];
    int barCount;
    int otherVar;
    void Add(*bar){
    barElem[barCount]=bar;
    barCount++;
    }
    //...
    foo myFoo;
    bar *myBar;
    myBar=new Bar(Argument);
    myFoo.Add(myBar);
    myBar=new Bar(Argument2);
    myFoo.Add(myBar);
    //...
    

    Das Problem ist jetzt: Wie kann ich den Zuweisungsoperator bauen? Wenn ich jetzt Foo auf ein anderes Element zuweise, würde ich nur die Pointer von Bar kopieren -->Ist immer noch (fast) das gleiche Objekt, statt dass ich jetzt 2 habe.
    Ansatz ist:

    Foo const& Foo::operator= (Foo const& src){
    	for(int i = 0;i < barCount; i++){
    		delete bar[i];
    	}
    	otherVar = src.otherVar;
    	barCount= src.barCount;
    	for(int i = 0;i < barCount; i++){
    		bar[i] = src.bar[i];
    	}
    	return *this;
    }
    

    Aber da habe ich ja das gleiche Problem.
    Und *bar[i] = *src.bar[i]; sollte zwar das problem lösen, nicht aber, wenn bar[i]=NULL ist (am Anfang sind alle NULL)
    und ein *bar[i]=new bar; vorher kann es doch nicht sein, oder?

    Ich muss dazusagen, dass die bar-Klasse ähnlich aussieht-->Das gleiche Problem.
    Bei beiden ist der Konstruktor überschrieben, da er zwingend Werte setzen muss.



  • Sowas ist meistens nicht wirklich Exceptionsicher.

    Schau dir mal das Copy/Swap Idiom an.



  • hm. läuft doch aber auch auf ein temporäres objekt hinaus. aber wozu sollte ein objekt erst initialisiert werden, wenn es dann von anderen werten überschrieben wird?

    Und was genau macht swap? Muss ich das selbst implementieren? Vertauscht es alles?
    also:
    swap(a,b){
    c=a;
    a=b;
    b=c;
    }

    oder nur eine zuweisung?
    Denn wenn es vertauscht, würde ich doch das argument ändern. Das will ich ja aber nicht.

    BTW: was macht eigendlich das & zeichen in:
    func foobar(const Param& myPar) ?
    Kenn ich nicht, weiß aber auch nicht, wie ich nach der Bedeutung suchen soll...

    Bzw: Kann ich das Problem nicht mit einer Liste umgehen? Die sollte doch schon sowas drin haben und ich brauch kein statisches array.



  • Flamefire schrieb:

    hm. läuft doch aber auch auf ein temporäres objekt hinaus. aber wozu sollte ein objekt erst initialisiert werden, wenn es dann von anderen werten überschrieben wird?

    Und was genau macht swap? Muss ich das selbst implementieren? Vertauscht es alles?
    also:
    swap(a,b){
    c=a;
    a=b;
    b=c;
    }

    oder nur eine zuweisung?
    Denn wenn es vertauscht, würde ich doch das argument ändern. Das will ich ja aber nicht.

    Lies dir den Wiki-Artikel zu Copy&Swap nochmal genauer durch bzw. google mal danach udn informier dich über die Funktionsweise. Wenn du die richtig nachvollziehen kannst wirst du erkennen, was da wirklich passiert.

    BTW: was macht eigendlich das & zeichen in:
    func foobar(const Param& myPar) ?
    Kenn ich nicht, weiß aber auch nicht, wie ich nach der Bedeutung suchen soll...

    Das nennt sich Referenz, d.h. Param wird nicht kopiert. Wie Referenzen funktionieren dürfte in deinem C++-Buch relativ weit vorne stehen.

    Bzw: Kann ich das Problem nicht mit einer Liste umgehen? Die sollte doch schon sowas drin haben und ich brauch kein statisches array.

    Je nachdem. Wenn du dein bisheriges foo kopierst, wird auch das array mit seinen Inhalten kopiert. Die Inhalte sind allerdings Pointer, und das worauf die Pointer Zeigen wird NICHT kopiert. Wenn du eine std::list<bar*> benutzt, wird eben die Liste mit ihren Inhalten kopiert, aber nicht das worauf die Pointer in der Liste zeigen. Das Problem nennt sich deep copy/shallow copy (google hilft weiter). Grundsätzlich dürfte aber die Verwedung eines geeigneten Containers trotzdem sicherer, einfacher und besser zu warten sein als das Array.



  • Ohje...ich versteh grade echt nicht, wie ich es auf mein problem anwenden soll.
    Ich habe ja dort eine Liste mit Pointern, deren Objekte jeweils kopiert werden sollen, in meinem Objekt.



  • Flamefire schrieb:

    Ich habe ja dort eine Liste mit Pointern, deren Objekte jeweils kopiert werden sollen, in meinem Objekt.

    Das ist dann der deep copy Fall 🙂



  • ok. Das sollte dann gehen.
    Kann ich das ganze auch so machen, dass ich eine liste von Objekten Speichere?
    also "list<bar> barElem;" benutze?
    wie müsste dann die Funktion zum Eintragen und benutzen aussehen?
    ich würde jetzt sowas machen:

    void Add(bar& newElem){
    barElem.push_back(newElem);
    barCount++;
    }
    //...
    foo myFoo;
    bar *myBar;
    myBar=new Bar(Argument);
    myFoo.Add(*myBar);
    myBar=new Bar(Argument2);
    myFoo.Add(*myBar);
    //...
    

    Wäre das so richtig und "gut", oder sollte ich es bei einer Liste von Pointer belassen?



  • Flamefire schrieb:

    Kann ich das ganze auch so machen, dass ich eine liste von Objekten Speichere?

    Sofern das geht, ist es meist die bessere Möglichkeit. Du musst nämlich nicht manuell Speicher verwalten und brauchst dich nicht mit den entsprechenden Problemen einzulassen. Sofern es nicht geht, nimm wenn möglich Boost.PointerContainer.

    An deinem Code sind mir ein paar Dinge aufgefallen:

    void Add(bar& newElem){ // Hier const bar&, also Referenz auf const-Objekt
    barElem.push_back(newElem);
    barCount++; // Unnötig, Grösse wird in barElem.size() gespeichert
    }
    //...
    foo myFoo;
    bar *myBar; // Warum Zeiger?
    myBar=new Bar(Argument); // Warum separate Zeile? Warum new?
    myFoo.Add(*myBar);
    myBar=new Bar(Argument2);
    myFoo.Add(*myBar);
    // Wo wird der Speicher freigegeben?
    //...
    

    Besser wäre:

    foo myFoo;
    myFoo.Add(Bar(Argument));
    


  • [Löschen. Doppelpost oO]



  • barCount: Ist richtig. Wird entfernt.
    zeiger: s. Unten
    Neue zeile: Ist um zu verdeutlichen, dass ich in der Funktion eine unbekannte anzahl Objekt erzeuge.
    Freigegeben: s. Unten
    BTW: Macht es einen unterschied, ob "const bar&" oder "bar const&" in der Param-Liste steht? Hab beides gesehn.

    ja vermutlich ist es besser.
    Das Problem ist, dass die Objekt im Laufe eines Parservorgangs entstehen.
    Sprich ich rufe eine Funktion mit einem text auf, die Funktion gibt mir ein Objekt zurück, dass ich dann an ein vorhandenes anhänge (Jeder Parameter, Unterfunktion usw. ist ein eigenes objekt)
    Darum ist das mit dem Pointer bequemer.
    Also:

    bar* Parse(text){
    CString func_name=text.Mid(...);
    //vieles mehr
    bar *res=new Bar(func_name);
    bar *sub=Parse(text.Mid(..));
    res->AddFunc(*sub);
    if(yy){
    sub=new Bar("const. Text");
    res->AddFunc();
    }
    //...
    res->type=55;
    //...
    return res;
    }
    

    Ist das so richtig, oder kann man es noch verbessern?
    Apropo:

    void Add(const bar& newElem){
    barElem.push_back(newElem);
    }
    

    oder:

    void Add(bar* newElem){
    barElem.push_back(*newElem);
    }
    

    Was ist besser für meinen Fall?

    Das ganze wird dann in die list<bar> gepackt (In AddFunc()) und der Hauptknoten ähnlich.
    Jetzt sollte doch, wenn ich den Hauptknoten freigebe, die Liste und damit alle Objekte rekursiv freigegeben werden, richtig?

    PS: Ich weiß, bin in C++ noch Anfänger. Mach sowas sonst mit Delphi (wo alles anders ist), nur hier geht es nicht, da ich etwas weiterführe und keine Lust habe Tonnen von Code zu portieren.

    EDIT: Ich habe es jetzt so gemacht, dass ich keine Pointer mehr übergebe. Rein von der Programmlogik scheint es zu funktionieren. Die Add Funktion lasse ich einen Pointer auf das Element in der List zurückgeben, dann kann ich es weiterverändern.


Anmelden zum Antworten