dynamische arrays in klassen



  • Naja ob mein Professor von den Regeln der großen 3 gehört hat weiß ich nicht. Und ich auch nicht.

    Die Aufgabe lautet, dass das Bingo Spiel variabel sein soll und wir mit dynamischer Speicherverwaltung arbeiten sollen. Das heißt n ist die Spieleranzahl und tip ist die Anzahl an möglichen Zahlen die im Spiel angekreuzt werden können. Es soll nämlich mit einer einstellbaren Spielermenge, einer einstellbaren Ankreuzmenge und einer einstellbaren Zahlenbereichsmenge gearbeitet werden. Und wir MÜSSEN es mit dynamischer Speicherverwaltung machen. Arrays und Vectoren akzeptiert der Prof nicht. Wie soll ich es sonst machen, wenn nicht mit einem 2 dimensionalen dynamischen Array?

    Die Globale Variable hab ich erstmal wieder raus gemacht. N und Tip werden nur von der Main übergeben.

    Naja ich denke ich probiere es mal mit 2 klassen.



  • Ich hab es jetzt mit 2 Klassen gemacht. Spieler und Bingo.
    Jetzt hab ich ein Problem das komischerweise erst eben auftritt seit ich das Programm neu gestartet habe. Ich hab nichts dran verändert und vorhin hat es funktioniert!

    Das ist der Konstruktor der bingo klasse:

    bingo::bingo(int playermnt,int count) {
    
        for(int i=0;i<playermnt;i++)
            player=new spieler(count);
    
    }
    

    Und der Spieler Klasse:

    spieler::spieler(int zahlen) {
        tippzettel=new int[zahlen];
        match=0;
    }
    

    Das Problem ist, dass sobald, player[1] aufgerufen wird und ich eine zahl eingeben will, das programm abbricht. Und ich kann einfach keinen Fehler finden.

    void bingo::setzen(int playermnt, int count, int max){
        for(int i=0;i<playermnt;i++){
            cout << "Spieler " << i+1 << " bitte Zahl zwischen 0 und " << max-1 << " setzen" <<endl;
            player[i].settip(count);
        }
    }
    
    void spieler::settip(int count){
        for(int i=0;i<count;i++){
            cout << "Zahl " << i+1 <<": ", cin >> tippzettel[i];
        }
    }
    

    Weiß jemand was da los ist?



  • new spieler(count) != new spieler[count]
    Ganz grosser Unterschied.
    Bei new int[zahlen] haste es ja auch richtig gemacht.

    Wobei das nächste, etwas schwieriger zu lösende Problem sein wird, dass du mit new spieler[count] dann vermutlich nen Compiler-Fehler bekommen wirst.

    BTW: Wieso mischt du Deutsch (spieler) und Englisch (player)?



  • hustbaer schrieb:

    new spieler(count) != new spieler[count]
    BTW: Wieso mischt du Deutsch (spieler) und Englisch (player)?

    Einfahc so. Hab da nicht so drauf geachtet.

    Das hab ich absichtlich so gemacht mit der Klammer. Ich hatte im Internet gelesen dass man das so macht. Oder so in der Art.
    Der Punkt ist, dass ich doch irgendwie den Konstruktor der Spielerklasse aufrufen muss. Und das mit jedem Spieler-Objekt, dass ich neu erstelle.
    Wenn ich schreibe:
    new spieler[count]

    dann erstellt er mir zwar ein Array aus Spielern, aber ich kann ja dann nicht den allgemeinen Konstruktor aufrufen.

    Ich habe vorhin eben nochmal meinen Prof gefragt. Weil er unbedingt dynamische Speicherverwaltung will.
    Ich hab es vorher mit einem 2 dim Dyn Array gemacht. Hat zwar funtkioniert, war aber etwas umständlicher. Da hat er mir empfohlen 2 Klassen zu erstellen. Aber jetzt hab ich wirklich keine Ahnung, wie das gehen soll. Die Anzahl Spieler und die Anzahl der Tippzettel soll variabel sein. Ich weiß beim besten Willen nicht wie er sich das vorstellt. Schon gar nicht mit dem, was wir bisher behandelt haben.



  • Ja, das war das was ich mit

    Wobei das nächste, etwas schwieriger zu lösende Problem sein wird, dass du mit new spieler[count] dann vermutlich nen Compiler-Fehler bekommen wirst.

    gemeint habe.

    Wie du es machen kannst: du kannst ein (dynamisch angefordertes!) Array aus Zeigern auf spieler machen, und dann die Spieler einzeln der Reihe nach konstruieren.
    Dann musst du beim Zusammenräumen natürlich auch erst alle Spieler einzeln löschen und dann zum Schluss nochmal das Array aus Zeigern.

    Etwas umständlicher, aber geht.

    (Wenn nicht so viel verboten wäre könnte man natürlich std::vector mit emplace_back() verwenden, und sich damit nen Haufen Murks sparen. Aber SO schlimm ist es ja auch nicht - gewöhn dir bloss nicht an so nen Mist zu machen wenn du es nicht so machen musst.)

    ps: Zweite Variante: verwende 2-Phase Construction. Ist im Allgemeinen verpönt, hier aber einfacher als die "Array aus Zeigern" Variante. D.h. du machst in dem (einzigen, parameterlosen) Konstruktor nix ausser brav alle Variablen mit "ungefährlichen" Werten zu initialisieren. Und machst dann eine eigene "Init" Funktion, an die du dann die Spieliernummer übergibst. Und rufst halt nach dem Erzeugen des Arrays die Init Funktion für jeden Spieler auf.



  • Oder placement-new:

    #include <cstddef>
    #include <type_traits>
    #include <memory>
    #include <iostream>
    
    class player_t
    {
    	private:
    		std::size_t const num_numbers;
    		unsigned * numbers;
    
    	public:
    		player_t( std::size_t num_numbers )
    		: num_numbers{ num_numbers },
    		  numbers{ new unsigned[ num_numbers ]() }
    		{}
    
    		player_t( player_t & ) = delete;
    
    		~player_t() { delete [] numbers; }
    };
    
    class bingo_t
    {
    	private:
    		typedef std::aligned_storage< sizeof player_t, std::alignment_of< player_t >::value >::type player_storage_t;
    
    		std::size_t const num_players;
    		player_t * players;
    
    	public:
    		bingo_t( std::size_t num_players, std::size_t num_numbers )
    		: num_players{ num_players },
    		  players{ reinterpret_cast< player_t * >( new player_storage_t[ num_players ] ) }
    		{
    			for( std::size_t i = 0; i < num_players; ++i )
    				new ( players + i ) player_t( num_numbers );
    		}
    
    		bingo_t( bingo_t & ) = delete;
    
    		~bingo_t() {
    			for( size_t i = 0; i < num_players; ++i )
    				players[ i ].~player_t();
    
    			delete [] reinterpret_cast< player_storage_t * >( players );
    		}
    };
    
    int main()
    {
    	bingo_t bingo( 10, 5 );
    }
    


  • Swordfish schrieb:

    class player_t
    {
    	private:
    		std::size_t const num_numbers;
    		unsigned * numbers;
    
    	public:
    		player_t( std::size_t num_numbers )
    		: num_numbers{ num_numbers },
    		  numbers{ new unsigned[ num_numbers ]() }
    		{}
    
    		player_t( player_t & ) = delete;
    
    		~player_t() { delete [] numbers; }
    };
    

    Auch du hast jede Menge Anti-Pattern angesammelt (const Member, falsche Reihenfolge der Member, private nach class, Kopierkonstruktor mit non-const-Referenz, Ro4 verletzt, _t für Typen, Braced initialisierung, etc.)



  • auch du mein sohn schrieb:

    const Member, falsche Reihenfolge der Member, private nach class [...], _t für Typen, Braced initialisierung, etc.

    mhm. passt schon.

    auch du mein sohn schrieb:

    Kopierkonstruktor mit non-const-Referenz, Ro4 verletzt

    Aha? Was ist denn möglich was nicht sein dürfte?



  • Swordfish schrieb:

    auch du mein sohn schrieb:

    Kopierkonstruktor mit non-const-Referenz, Ro4 verletzt

    Aha? Was ist denn möglich was nicht sein dürfte?

    Wie viele Zeilen musst du ändern, um einen Move-Konstruktor hinzuzufügen?



  • Verrats mir ...



  • (unsinn-entfernt)



  • Du sorry, ich steh vermutlich auf diversen Leitungen herum ... was meinst?



  • Nix, vergiss es. Ich war geistig im falschen Thread.



  • Okay also ich habs jetzt. Ich hab jetzt einfach in der Spielerklasse einen Konstruktor ohne Argumente verwendet! So funktionierts dann.
    Und was diese Antipattern Fehler betrifft. Wird da denn bei mir als blutiger Anfänger schon so sehr drauf geschaut?


  • Mod

    Cabooze schrieb:

    Und was diese Antipattern Fehler betrifft. Wird da denn bei mir als blutiger Anfänger schon so sehr drauf geschaut?

    Im Prinzip ja. Erstens sieht man da dran, dass du vermutlich einen schlechten Lehrer hast und wahrscheinlich nur wenig Brauchbares und viel Falsches von ihm lernen wirst. Zweitens sind erfahrungsgemäß die Sachen, die du dir zu Anfang angewöhnst prägend für deinen späteren Stil und du kannst sie dir nur schwer abgewöhnen (es ist aber möglich, aber es ist viel Disziplin nötig). Denn wenn du später doch mal umlernen möchtest, dann bist du anderweitig schon viel weiter als diese Anfängerthemen und schreibst viel komplexere Programme als die typischen Anfängerübungen. Und dann wird es dir schwer fallen, dass du diese (für dich) bewährten Techniken nicht mehr einsetzt, denn diese funktionieren aus deiner Sicht wenigstens, wohingegen du die "richtigen" Techniken nie richtig an einfachen Beispielen geübt hast und in den Programmen, die du dann schreibst, nicht richtig einzusetzen vermagst.


Anmelden zum Antworten