Mehrdimensionale Arrays löschen
-
Ich habe in einer Klasse ein zweidimensionales Array, welches Zeiger speichert.
Jetzt möchte ich gerne im Destruktor dieses Array löschen.Also habe ich mal etwas gesucht und im Forum diesen Link gefunden.
Ich habe dann die erste Moeglichkeit probiert, sodass immer eine Zeile geloescht wird und danach das Feld.
Im folgenden werde ich erklären, welche Meldungen kamen und wie mein code genau war.
1. Initialisierung des Arrays mit
Spielstein* brett[ZEILEN][SPALTEN];
Löschen mit:
#ifdef DEBUG std::cout << "DEBUG: Loesche Brett" << std::endl; #endif for (int j = 0; j < ZEILEN ; j++) delete [] brett[j] ; delete [] brett;
Fehlermeldung:
DEBUG: Loesche Brett *** glibc detected *** ./4gx: free(): invalid pointer: 0x00007fff005d5a38 *** ======= Backtrace: ========= /lib64/libc.so.6[0x7f7fe2066108] /lib64/libc.so.6(cfree+0x76)[0x7f7fe2067c66] ./4gx[0x401ee1] ./4gx[0x401fe5] ./4gx[0x4017e1] /lib64/libc.so.6(__libc_start_main+0xe6)[0x7f7fe2010586] ./4gx[0x401219] ======= Memory map: ======== 00400000-00404000 r-xp 00000000 00:14 10461713 /home/lumbeck/NetBeansProjects/4GX/4gx 00603000-00604000 r--p 00003000 00:14 10461713 /home/lumbeck/NetBeansProjects/4GX/4gx 00604000-00605000 rw-p 00004000 00:14 10461713 /home/lumbeck/NetBeansProjects/4GX/4gx 00605000-00626000 rw-p 00605000 00:00 0 [heap] 7f7fdc000000-7f7fdc021000 rw-p 7f7fdc000000 00:00 0 7f7fdc021000-7f7fe0000000 ---p 7f7fdc021000 00:00 0 7f7fe1ff2000-7f7fe2141000 r-xp 00000000 08:03 1247766 /lib64/libc-2.9.so 7f7fe2141000-7f7fe2341000 ---p 0014f000 08:03 1247766 /lib64/libc-2.9.so 7f7fe2341000-7f7fe2345000 r--p 0014f000 08:03 1247766 /lib64/libc-2.9.so 7f7fe2345000-7f7fe2346000 rw-p 00153000 08:03 1247766 /lib64/libc-2.9.so 7f7fe2346000-7f7fe234b000 rw-p 7f7fe2346000 00:00 0 7f7fe234b000-7f7fe2361000 r-xp 00000000 08:03 1247727 /lib64/libgcc_s.so.1 7f7fe2361000-7f7fe2561000 ---p 00016000 08:03 1247727 /lib64/libgcc_s.so.1 7f7fe2561000-7f7fe2562000 r--p 00016000 08:03 1247727 /lib64/libgcc_s.so.1 7f7fe2562000-7f7fe2563000 rw-p 00017000 08:03 1247727 /lib64/libgcc_s.so.1 7f7fe2563000-7f7fe25b8000 r-xp 00000000 08:03 1247770 /lib64/libm-2.9.so 7f7fe25b8000-7f7fe27b7000 ---p 00055000 08:03 1247770 /lib64/libm-2.9.so 7f7fe27b7000-7f7fe27b8000 r--p 00054000 08:03 1247770 /lib64/libm-2.9.so 7f7fe27b8000-7f7fe27b9000 rw-p 00055000 08:03 1247770 /lib64/libm-2.9.so 7f7fe27b9000-7f7fe28aa000 r-xp 00000000 08:03 1141456 /usr/lib64/libstdc++.so.6.0.10 7f7fe28aa000-7f7fe2aa9000 ---p 000f1000 08:03 1141456 /usr/lib64/libstdc++.so.6.0.10 7f7fe2aa9000-7f7fe2ab0000 r--p 000f0000 08:03 1141456 /usr/lib64/libstdc++.so.6.0.10 7f7fe2ab0000-7f7fe2ab2000 rw-p 000f7000 08:03 1141456 /usr/lib64/libstdc++.so.6.0.10 7f7fe2ab2000-7f7fe2ac5000 rw-p 7f7fe2ab2000 00:00 0 7f7fe2ac5000-7f7fe2ae3000 r-xp 00000000 08:03 1247870 /lib64/ld-2.9.so 7f7fe2cbf000-7f7fe2cc2000 rw-p 7f7fe2cbf000 00:00 0 7f7fe2cde000-7f7fe2ce2000 rw-p 7f7fe2cde000 00:00 0 7f7fe2ce2000-7f7fe2ce3000 r--p 0001d000 08:03 1247870 /lib64/ld-2.9.so 7f7fe2ce3000-7f7fe2ce4000 rw-p 0001e000 08:03 1247870 /lib64/ld-2.9.so 7fff005c3000-7fff005d8000 rw-p 7ffffffea000 00:00 0 [stack] 7fff005ff000-7fff00600000 r-xp 7fff005ff000 00:00 0 [vdso] ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall] Aborted
Wer kann helfen?
Oder sollte ich brett ganz anders erstellen?
-
Das Array ist ein 2-dim Array von Pointern und wird insofern falsch initialisiert. Richtige Initialisierung: siehe von Dir angegebenen Link.
-
Mich wundert´s, warum es zu zweidimensionalen Arrays noch keine FAQ, gibt, vielleicht setz´ ich mich ja mal irgendwann hin und schreib´ eine. Die Frage nach zweidimensionalen Arrays ist wohl die häufigste, die hier gestellt wird.
Wenn du die boost Bibliotheken verwenden kannst findest du dort die Klasse multi_array, die N-dimensionale Arrays implementiert.
Falls du kein boost hast kannst du die Überlegung anstellen, dass sich jedes N-dimensionale Array linearisieren lässt, z.B. hat ein Array der Größe 4x2 8 Elemente, wobei die Elemente folgende Indizes besitzen:
`
+---+---+---+---+
| 0 | 1 | 2 | 3 |
+---+---+---+---+
| 4 | 5 | 6 | 7 |
+---+---+---+---+
`
Damit lässt sich jetzt einfach eine Klasse bauen, die ein 2-dimensionales Array implementiert:
#include <vector> template<typename T> class array2D { public: array2D() : Rows_( 0 ), Cols_( 0 ) { } array2D( unsigned int Rows, unsigned int Cols ) : Rows_( Rows ), Cols_( Cols ), Data_( Rows * Cols ) { } unsigned int rows() const { // Anzahl der Zeilen zurückgeben return Rows_; } unsigned int cols() const { // Anzahl der Spalten zurückgeben return Cols_; } // const und non-const Zugriff auf Elemente im Array T& operator()( unsigned int Row, unsigned int Col ) { // Zugriff über linearisierten Index return Data_[Row * cols() + Col]; } const T& operator()( unsigned int Row, unsigned int Col ) const { // Zugriff über linearisierten Index return Data_[Row * cols() + Col]; } void resize( unsigned int Rows, unsigned int Cols ) { // !! TO DO !! // durch die Änderungen der Ausdehnung einer Dimension verschiebt // sich der lineare Index der Elemente, die resize() Methode braucht // etwas mehr Intelligenz. Rows_ = Rows; Cols_ = Cols; Data_.resize( Rows * Cols ); } private: unsigned int Rows_; unsigned int Cols_; std::vector<T> Data_; };
Damit lässt sich dein Spielbrett dann so verwalten:
int main() { array2D<Spielstein> Spielbrett( 8,8 ); // 8x8 Felder groß // Bsp.: Farbzuweisung an Spielstein Spielbrett( 0,0 ).Farbe = Color.Red; // Bsp.: Zuweisung an Array Spielstein NeuerStein; NeuerStein.Farbe = Color.Green; Spielbrett( 2,7 ) = NeuerStein; }
Die array2D Klasse ist natürlich nur rudimentär implementiert, man kann sich noch nach Herzenslust austoben (zeilen- und spaltenorientierte Iteratoren, Stream Iteratoren, etc., pp.).
-
EDIT: Dieser Text bezieht sich nur auf die erste Antwort.
Ich probiere nun die Initialisierung mit der 1. Möglichkeit.
Also:
static const int ZEILEN=7; static const int SPALTEN=6; Spielstein*** b=new Spielstein**[ZEILEN]; for(int i=0;i<ZEILEN; i++) { b[i]=new Spielstein*[SPALTEN]; }
Fehlt da noch wo ein * in
b[i]=new Spielstein*[SPALTEN]
oder wieso wirds nicht richtig initialisiert?
Fehler ist aber diesmal:Spielbrett.h:74: error: `new' cannot appear in a constant-expression Spielbrett.h:74: error: ISO C++ forbids initialization of member 'b' Spielbrett.h:74: error: making 'b' static Spielbrett.h:74: error: invalid in-class initialization of static data member of non-integral type 'Spielstein***'
Und weitere Folgefehler...
--------
Okay, ich werde es mal so probieren mit dem Vector. Und statt des Objektes kann ich auch die Adresse speichern, also den Typ Spielstein* angeben, richtig?
-
static const int ZEILEN=7; static const int SPALTEN=6; Spielstein** b=new Spielstein*[ZEILEN]; for(int i=0;i<ZEILEN; i++) { b[i]=new Spielstein[SPALTEN]; }
Brauchst natürlich nen Standardkonstruktor für die Spielsteine...
EDIT: Wie ist denn b definiert?
-
Fabulus schrieb:
Spielstein* brett[ZEILEN][SPALTEN];
Hier ist ggf. ein delete für die einzelnen Spielsteine notwendig, falls diese per new erzeugt wurden und nicht anderweitig verwaltet werden. Das Array selbst ist ein automatisches Objekt (oder ein Member einer Klasse), ein delete darf diesbezgl. nicht erfolgen.
Fabulus schrieb:
static const int ZEILEN=7; static const int SPALTEN=6; Spielstein*** b=new Spielstein**[ZEILEN]; for(int i=0;i<ZEILEN; i++) { b[i]=new Spielstein*[SPALTEN]; }
Fehlt da noch wo ein * in
b[i]=new Spielstein*[SPALTEN]
oder wieso wirds nicht richtig initialisiert?
Der Fehlermeldung nach sieht das eher so aus, als ob du die Initialisierung direkt in der Klassendefinition durchführen willst.
-
Also ich habe jetzt erst einmal die Klasse array2D geschireben, wie es hier aufgefuehrt wurde.
Aber es gibt hier jetzt bei der Erstellung dieses Arrays ein Problem:
Ich erstelle mir:
array2D<Spielstein*> bret( 6,7 );
Und es kommt:
Spielbrett.h:77: error: expected identifier before numeric constant Spielbrett.h:77: error: expected ',' or '...' before numeric constant
Sofern ich schreibe (was auch im Endeffekt mein Ziel ist):
array2D<Spielstein*> bret( ZEILEN,SPALTEN );
kommt:
Spielbrett.h:77: error: 'ZEILEN' is not a type Spielbrett.h:77: error: 'SPALTEN' is not a type
ZEILEN und SPALTEN sind static const int zwei Zeilen darüber erstellt.
-
Bitte hinreichend vollständigen Code zeigen. Meine Kristallkugel ist schon vor Jahren zu Bruch gegangen.
-
Meine array2D.h sieht genauso aus, wie von DocShoe beschrieben.
Ich habe mir ein testprogramm geschrieben, in dem ints in einem array dieser Art gespeichert werden. Das klappt soweit.
Verwende ich aber das Array in meiner Spielbrett.h, kommt der eben beschriebene Fehler, auch wenn integer die Elemente sein sollen.Hier mal der Code:
#ifndef SPIELBRETT_H #define SPIELBRETT_H #include "Spielstein.h" #include "array2D.h" const int Z=6; const int S=7; class Spielbrett { public: Spielbrett() { init(); } ~Spielbrett() { } // destructor void init(); Spielstein& getStein(const int& x, const int& y) const { return *brett[x][y]; } // Getter-Methoden const int& getZeilen() const { return ZEILEN; } const int& getSpalten() const {return SPALTEN; } // Umleitung des Ausgabeoperators std::ostream& outputToStream(std::ostream& ostr) const; int getNextZeile(const int& y) const; // Holt sich die naechste Zeile in Spalte y bool setzeStein(const int& y, Spielstein& stein); // Setzt Stein in Zeile y private: // Hoehe und Breite des Feldes festlegen static const int ZEILEN=Z; static const int SPALTEN=S; /* ZEILE 77 */ array2D<int> bret(6,7); Spielstein* brett[ZEILEN][SPALTEN]; };
Die Methoden beziehen sich alle noch auf das alte brett, was aber sonst funktioniert.
-
Wer ist denn überhaupt Besitzer des Spielsteins? Irgendwas muss ja verantwortlich sein für die Erzeugung und Zerstörung der Spielsteine, wenn du keine Zeiger, sondern die Spielstein Klasse als Template Parameter benutzt erledigt das array2D für dich.
Edit:
Du kannst das array nicht statisch initialisieren, wie es in Zeile 77 geschieht. Benutz´ stattdessen die Initialisierungsliste des Konstruktors:class Spielbrett { array2d<Spielstein> Spielsteine_; public: Spielbrett() : Spielsteine_( 6,7 ) { } }
-
Fabulus schrieb:
Ich erstelle mir:
array2D<Spielstein*> bret( 6,7 );
Und es kommt:
Spielbrett.h:77: error: expected identifier before numeric constant Spielbrett.h:77: error: expected ',' or '...' before numeric constant
Für die Initialisierung ist der Konstruktor zuständig. Die Fehlermeldung besagt nur, dass der Compiler eine Typenliste erwartet, weil es sich nach der öffnenden Klammer dort nur um eine Funktionsdeklaration handeln kann.
-
Was meinst du mit "Wer ist Besitzer"? Ich gebe mal zur Ergänzung die Klasse Spielstein an (ist abstrakt, aber das sollte ja kein Problem sein).
Das große Problem ist dass auch beispielsweise keine Integer-werte im Array speichern kann (so wie oben mal gepostet). Es kommt trotzdem dieser Fehler
class Spielstein { public: virtual ~Spielstein() {} virtual int getColor() const { return farbe; } virtual bool isSet() const=0; enum Color {grau, rot,blau,gelb}; protected: Color farbe; };
In einem normalen Array kann ich ja auch die Adressen speichern
Wenn ich übrigens in meiner Testdatei dieses Array mit <Spielstein*> erstelle, klappt alles wunderbar.
-
Hab meinen Post gerade editiert, da sollte die Lösung drinstehen.
Der Besitzer der Spielsteine ist das Ding, das mit new die Spielsteine erzeugt und in das Spielbrett einfügt. Wenn du einen Zeigertyp als Template Parameter für array2D benutzt enthält das array2D Objekt nur Nullpointer.
-
Ok, ich habe jetzt den Vector soweit erstellt und allen Elementen eine passende Adresse ausgegeben.
Muss ich jetzt dennoch dafür einen Destruktor schreiben, oder löscht der Compiler jetzt die Elemente von selber? Also ein Destruktor von der Klasse Spielbrett. Weitere Zeiger oder dynamische Speicher kommen nicht vor.Eine andere Frage zur Klasse vector. Soweit ich richtig gesucht habe, gibt es noch keine Methode, um den Inhalt eines Vectors in einen anderen zu kopieren.
Also habe ich gedacht, ich schreibe mir so eine. Natürlich bin ich dort auf den Iterator gestoßen, der jedes Element einzeln durchgeht.Da meine Klasse in einem Headerfile steht, muss ich mit std::vector<T>::iterator it den Iterator erstellen.
Dies klappt aber soweit nicht. Darf ich denn überhaupt doppelt scopen? Wie umgehe ich das Problem?
Der Code ist ganz einfach bisher:
void copy(array2D<T>& arr) { std::vector<T>::iterator it=Data_.begin(); // Erstelle iterator std::vector<T>::iterator it2=arr.Data_.begin(); // Erstelle zweiten Iterator /* Pruefe nach, ob Groesse ausreicht (TODO) */ while(it!=Data_.end()) { *it2=*it; it++; it2++; } }
Als Fehler kommt:
array2D.h: error: expected ';' before 'it' array2D.h: error: 'it' was not declared in this scope array2D.h: error: expected ';' before 'it2' array2D.h: error: 'it2' was not declared in this scope