Problem mit Anwendung von erase()



  • Ich habe gerade etwas mit Vectoren gearbeitet und bin auf ein Problem gestoßen bei dem ich etwas Unterstützung gebrauchen könnte 🙂
    Wenn ich einen vector mit Objekten einer Klasse fülle, welcher ich im Konstruktor Referenzen übergebe, dann gelingt es mir nicht erase() anzuwenden um anschließend die Objekte wieder zu löschen 😉
    Hier mein Problem kurz dargestellt:

    Main:

    int main()
    {
    	int a = 2;
    	int b = 3;
    
    	std::vector <test> vec;
    
    	test o1 = test(a, b);
    	vec.push_back(o1);
    	test o2 = test(a, b);
    	vec.push_back(o2);
    
    	vec.erase(vec.begin() + 1);
    
    	system("pause");
    	return 0;
    }
    

    Header der externen Klasse:

    class test
    {
    public:
    	test(int &r_a, int &r_b);
    
    	int &a;
    	int &b;
    };
    

    Cpp Datei der externen Klasse:

    test::test(int &r_a, int &r_b)
    	:a(r_a), b(r_b)
    {
    }
    

    Ich kann mit den Referenzen Problemlos arbeiten und alles funktioniert reibungslos 🙂 Jedoch gelingt es mir nicht das Objekt wieder zu löschen 🙂

    Fehlermeldung:
    Die Funktion 'Operator=' ist in 'test' nicht verfügbar

    Danke im voraus für eure Hilfe 😉



  • der vector muss ja intern die objekte verschieben (->zuweisen), wenn du zwischendrin etwas löschst.

    d.h. er braucht test::op=
    der wiederrum kann aber nicht generiert werden(wegen der referenzen; sollte dich dein compiler(ggf. -W4 bzw -wall o.ä.) aber warnen).
    also brauchst du entweder einen selbst definierten op= oder nen move-ctor.

    spielst du nur rum oder willst du was bestimmtes erreichen?



  • unskilled schrieb:

    spielst du nur rum oder willst du was bestimmtes erreichen?

    Nein, hab nur eine vereinfachte Version meines Codes geschrieben um den hier zu demonstrieren 😉 Ich habe in einer Klasse im Konstruktor mehrere Objekte in einen Vector verschieben lassen 😉 und möchte dann im Verlauf des Codes mein Objekt wieder aus dem Vector löschen um Speicher freizugeben 😉 Irgendwie komm ich nicht so gut klar damit 😉



  • Ich könnte eventuell auch die Referenzen erst später übergeben (den Funktionen selbst) und nicht schon im Konstruktor dann würde es funktionieren 😉 Wäre dann halt eine Notlösung 😉 Jemand eine Idee für mich ? 😞



  • Und warum möchtest du unbedingt eine Referenz im Objekt verwalten?

    Also warum tut es nicht einfach

    class test
    {
    public:
        test(const int& r_a, const int& r_b);
    
        int a;
        int b;
    };
    

    Gruß,
    Klaus.



  • Klaus82 schrieb:

    Und warum möchtest du unbedingt eine Referenz im Objekt verwalten?

    Ich programmiere an einem Spiel und dieses Objekt ist sozusagen ein Gegner, der bei jedem Frame Daten des Spielers einliest, und aber auch Verändert (Schaden usw.) 🙂 aus dem Grund bräuchte ich die Referenz und dachte mir ich übergebe sie im Konstruktor 😉

    Eine konstante Referenz hilft mir auch nicht besonders weil ich das Objekt auf welches ich die Referenz erstellt habe ja verändern möchte 🙂

    LG Mafyou



  • Zeiger?



  • Und warum braucht der 'Gegner' dann die Klasse vom Spieler? Kann die Klasse Gegner nicht eine Funktion haben, die Schaden austeilt, was über eine Funktion der Klasse 'Spieler' als 'einstecken' übernommen wird?

    /* Pseudocode */
    spieler.einstecken( gegner.schaden() );
    

    Gruß,
    Klaus.



  • Ich habe jetzt mal was zusammengebastelt, die Experten dürfen mich jetzt für die Benutzung von raw-pointern bashen. 😃

    #include <iostream>
    #include <memory>
    #include <vector>
    
    class SPIELER {
    	public:
    
    	  SPIELER(double lp):LP(lp){}
    		void einstecken(double schaden)
    		  { LP -= schaden; }
    		int lebenspunkte() { return LP; }
    
    	private:
    		int LP;
    };
    
    class GEGNER {
    	public:
    		GEGNER( SPIELER* s ):sp( s ){}
        void hauen() 
    		  { sp -> einstecken( 4 ); }
      private:
    		SPIELER* sp;
    };
    
    int main() {
    
    	/* Lege Spieler mit 10 LP an */
    
    	SPIELER Tim( 10 );
    
    	std::cout << "Tim hat " << Tim.lebenspunkte() << " Lebenspunkte!" << std::endl;
    
    	SPIELER* p_tim = &Tim;
    
      /* Lege Gegner Ork an, der sich Tim vornimmt */
    
    	GEGNER Ork( p_tim );
    
    	Ork.hauen();
    
    	std::cout << "Tim hat " << Tim.lebenspunkte() << " Lebenspunkte!" << std::endl;
    
    	return 0;
    }
    


  • Nö, das ist völlig in Ordnung. Du hast ja keine Pointer die Objekte "besitzen" und dafür sind rohe Pointer ok. Nur wenn du mit new/delete anfängst sollte man über Smart Pointer nachdenken.



  • Danke an alle für die Hilfe ich habs jetzt zum laufen bekommen 😋



  • Super, dann habe ich noch eine Frage. 😃

    Ich würde ja gerne den Sinn (und Unsinn?) von Templates besser verstehen. Mir ist der Sinn schon klar, dass diese sehr flexibel sind, aber ab wann fängt man an mit einem Template zu arbeiten. Auf jeden Fall immer?

    Ich kann die Klasse SPIELER auch als Template schreiben und die Lebenspunkte als Parameter T offen lassen, aber wäre das mit Kanonen auf Spatzen geschossen?

    Gruß,
    Klaus.

    template <typename T>
    class SPIELER {
    	public:
    
    	  SPIELER(double lp):LP(lp){}
    		void einstecken(T schaden)
    		  { LP -= schaden; }
    		T lebenspunkte() { return LP; }
    
    	private:
    		T LP;
    };
    


  • Ein Template ist ja nur eine Schablone für Klassen.
    Jedes Spieler<1>, Spieler<99>,... erzeugt eine eigene Klasse.

    Wenn du jetzt eine fest Anzahl an verschiedenen Spieler hast, würdest du doch wahrscheinlich auch keine n Klassen Spieler_LP1, SpielerLP_99, ... anlegen.

    Also ich sehe keinen Sinn hier für ein Template, sondern nur Nachteile.
    Named-Konstruktor wäre hier eine sinnvolle ALternative:

    createHeavyPlayer();
    createTinyPlayer();...
    


  • Dein Template Beispiel ist eher nicht so sinnvoll. Das was dein Template Parameter festlegt ist ja der Typ für Lebenspunkte. Und in deinem Programm wird es wohl kaum den Fall geben das du Spieler mit verschiedenen Typen (float/int) für Lebenspunkt nutzt, sondern dich eher auf eines von beidem festlegst. Wenn du es für später flexibel halten möchtest würde ich eher ein typedef nutzen.

    Templates machen meiner Meinung nach nur Sinn wenn die Klasse allgemein genug ist, dass man sie wirklich mit verschiedenen Typen nutzt. Also z.B. ein 2D Vektor für Positionen. Manchmal will man eben nur ganzzahlige Werte abdecken und manchmal braucht man floats. Oder jede Art von Containern, denn die wären ohne Templates nur sehr blöd zu implementieren.


Log in to reply