dynamische arrays in klassen
-
Swordfish schrieb:
Natürlich kann man einen
T*
(Sternchen nach belieben hinzufügen) an eine Funktion übergeben, genauso wie einT[N]
. Der Zeiger aufT
bleibt ein Zeiger aufT
und das ArrayT[N]
zerfällt in einen Zeiger aufT
.Cabooze schrieb:
Oder anders gefragt: ist es doch irgendwie möglich ein dynamisches Array von objekten zu erstellen?
Nimm einen std::vector<> wenn du das darfst.
Nope. Darf ich leider nicht.
Also mit dem dynamischen Array hab ich es jetzt so versucht:
Lotto::Lotto(int zahl, int spieler) { pl_tip=new int*[spieler]; for(int i=0;i<spieler;i++) pl_tip=new int[zahl]; }
Also das ist der Konstruktor. Leider funktioniert das nicht.
}
-
Lotto::Lotto(int zahl, int spieler) { pl_tip=new int*[spieler]; for(int i=0;i<spieler;i++) pl_tip[i]=new int[zahl]; }
-
Swordfish schrieb:
Lotto::Lotto(int zahl, int spieler) { pl_tip=new int*[spieler]; for(int i=0;i<spieler;i++) pl_tip[i]=new int[zahl]; }
Ok danke. Wie greife ich nun noch darauf zu?
mit *pl_tip[i] müsste ich ja auf das innere Array zugreifen. Aber wie greife ich auf das äußere zu? Nur pl_tip[i] funktioniert leider nicht.
-
Sag mal, habt ihr kein Buch/Skriptum/sonstwas?
pl_tip[spielerindex][zahlindex]
-
Swordfish schrieb:
Sag mal, habt ihr kein Buch/Skriptum/sonstwas?
pl_tip[spielerindex][zahlindex]
Wir haben 2 dim dynamische Arrays nicht durchgenommen. Deswegen frage ich ja.
Und die Aufgabe verlangt deutlich dynamische Speicherverwaltung mit variabler anzahl an spielern und zahlen.
Ich wüsste nicht wie es ohne so ein Array gehen soll.So klappt dann soweit. Danke für deine Hilfe
-
Ich versuche jetzt gerade ein 2 dim dyn Array mit einem destructor zu löschen.
Im Konstruktor wird folgendes 2 dim Array erstellt:
bingo::bingo(int n, int tip) { spieler = new int*[n]; for (int i = 0; i < n; i++) spieler[i] = new int[tip]; }
Und mein destructor sieht folgendermaßen aus.
bingo::~bingo() { int n, tip; for(int i=0;i<n;i++) delete [] spieler[i]; delete [] spieler; }
Ich habe n und tip als Globale variablen deklariert in der Header File. Mit
extern int n, tip;
Allerdings funktioniert es nicht. N und Tip werden in der Main aufgerufen und eingegeben. Allerdings kommt für n im Destruktor immer 0 raus.
Woran liegt das?
-
Cabooze schrieb:
Allerdings funktioniert es nicht. N und Tip werden in der Main aufgerufen und eingegeben. Allerdings kommt für n im Destruktor immer 0 raus.
Woran liegt das?Weil du mit globalen Variablen und selbstgefrickelter dynamischer Speicherverwaltung so ziemlich alles an Antipattern angesammelt hast, was in eine Programm dieser Größe passt. Ich wette, du hast mindestens die Regel der großen Drei missachtet, sofern dein Lehrer überhaupt selbst jemals davon gehört haben sollte. Nachdem du diesen Fehler korrigiert hast, kann man weiter gucken.
Die nächste Baustelle sind die globalen Variablen, von denen man besser wissen sollte, wie die Regeln zur Namensauflösung sind, wenn man sie schon benutzt (und man sollte sie in aller Regel nicht nutzen, wenn es sich vermeiden lässt). Du scheinst nämlich nicht zu wissen, welcher Bezeichner in deinem Programm sich an welcher Stelle auf welches Objekt bezieht.Warum überhaupt diese komischen Doppelzeiger, wenn doch letztlich alle "Zeilen" der Datenstruktur gleich lang sind. Da kann man doch besser einen einzigen, zusammenhängenden Speicherblock der Größe (Anzahl Zeilen) * (Anzahl Spalten) nehmen und spart sich dadurch viel Aufwand, sowohl was die Programmierung angeht, als auch bezüglich der Effizienz des resultierenden Programms. Abgesehen davon ist dynamische Speicherverwaltung kein Teil einer Lottoklasse. Was auch immer eine Lottoklasse überhaupt genau tun soll. Aber es ist gewiss nicht Speicherverwaltung, denn wie viele echte Lotto hast du schon gesehen, die Speicher verwalten? Das gehört in eine eigene Klasse. Und an der absurden Frage zu den echten Lottos, die du schon gesehen hast, merkst du auch, dass diese Klasse vielleicht nicht so sonderlich gut designt ist, denn es ist nicht klar, was sie überhaupt darstellen soll.
-
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.
Beinew 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
mitemplace_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.