vector < vector <float> > nachträglich initalisieren



  • Hallo,

    ich habe in einer Klasse den Vektor

    vector<vector<float>> V;
    

    diesen möchte ich nun im Konstruktor zB auf die Dimension V[int a][int b] setzen.
    Dies versuche ich mit:

    V.reserve(a);
    for (int i = 0; i < a; ++i)	{	V[i].reserve(b);	}
    

    Allerdings bekomme ich in meinem Hauptprogramm, nach dem Erstellen der Klasse, beim Setzen des ersten Elements

    V[0,0] = float c
    

    immer den Fehler:

    Program received signal SIGSEGV, Segmentation fault.

    Was ich so interpretiere, dass ich die Vektoren nicht (ausreichend) initalisiert bzw. Speicher zugewiesen habe.😕

    Kann mir hier jemand - trotz der Feiertage 🙂 - helfen?

    Vielen Dank,
    tillt


  • Mod

    Dein Program hat undefiniertes Verhalten, da reserve Speicher nur alloziert, nicht aber direkt für den Nutzer verfügbar macht - es verhindert nur nachträgliche Reallokation des Speichers. Schau dir resize an. (PS: Ist der zweite Schnipsel dein Ernst?)



  • Guten Morgen Arcoth, danke erstmal für deine Antwort.
    Ich habe noch nie mit Vektoren gearbeitet und habe anscheinend das Prinzip der Speicherreservierung noch nicht verstanden 😉
    Wenn ich davon ausgehe, dass ich mit dem Erstellen der Klasse und damit dem Erstellen des Vektors schon Speicher reserviert habe und diesen mit resize() nur noch anpassen muss, währe die Lösung, im Konstruktur einfach:

    V.resize(a);
    

    zu schreiben. Allerdings bekomme ich dann die selbe Fehlermeldung und der Compiler verweisst auf die selben Zeilen wie oben. Neben der entprechenden Zeilen im Code auch in stl_vector.h auf

    { return *(this->_M_impl._M_start + __n); }
    

  • Mod

    Kannst du ein vollständiges Minimalbeispiel zeigen?

    Es klingt ein bisschen so, als gingst du falsch an die Sache ran. Beim vector geht es ja teilweise gerade darum, dass du dich nicht um Speicherreservierung kümmern brauchst. Denk nicht so sehr wie in C! Füll den vector mit den Objekten, die du drin haben möchtest (zum Beispiel mittels push_back, emplace, und vielen andere Methoden). Irgendwelche "leeren" Objekte im vector zu erzeugen und diese dann mit den eigentlich gewünschten Objekten zu ersetzen ist oft nicht richtig. Pack einfach gleich den richtigen Inhalt rein!



  • Danke SeppJ, wenn ich die Zuweisung durch

    V[a=0].push_back(b)
    

    ersetze, bekomme ich einen Fehler beim Ausführen auf die Zeile. Im eindimsionalen Vektorfall

    V.push_back(a)
    

    funktioniert es.

    Was ich für mein Programm benötige ist, dass ich - wie mit einen normalen Array - einen spezifischen Wert in V[a][b] sowohl setzen als auch lesen kann.

    Rein theoretisch könnte ich natürlich über "Umwege" erstmal den Vektor an mit allen entsprechenden Inhalten des Arrays b befüllen. Aber dann könnte ich Vektoren ja gleich umgehen....





  • meinst du damit, dass ich meinen vollständigen Code posten soll oder das ich einfach höflich um ein Codebeispiel bitten soll? 😕

    Einen Compilerfehler schließe ich aus, da das Programm ja kompilliert wird, und dann beim Ausführen abbricht.



  • Weder, noch. Aber das steht ja alles in dem Link.



  • okay 🙄 let´s try:

    Meine Klasse:

    class Plate	{
    	int fields;
    	vector<vector<float> > absorb;
    
    	public:
    		Format* format = bookOut->addFormat();
    		Font* font = bookOut->addFont();
    		void set_plate(int wave, int field_num);
    		void setField(int wave, int field, float density);
    		float getField(int wave, int field);
    		Format* set_format(int num);
    };
    

    Mein "Konstruktor" ..ich weiß eigentlich eine Klassenfunktion.

    void Plate::set_plate(int wave, int field_num)	{
    	absorb.resize(wave);
    	//for (int i = 0; i < wave; ++i)	{	absorb.reserve(field_num);	}
    };
    

    Die zu nutzenden Funktionen:
    [i] absorb[wave].push_back(density); steht in Zeile 75 *

    void Plate::setField(int wave, int field, float density)	{
    	//absorb[wave][field] = density;
    	absorb[wave].push_back(density);
    
    };
    
    float Plate::getField(int wave, int field)	{
    	return	absorb[wave][field];
    };
    

    Und der Aufruf der fehlschlägt in meiner main():

    P[current_plate].setField(i, 0, sheetIn->readNum(row+3, col+2));
    

    Wobei current_Plate = (int) 0, i = 0 und sheetIn->readNum(row+3, col+2) ein float Wert.

    Ich hoffe das reicht, um mein Problem nachzuvollziehen. Die Fehlermeldung hatte ich bereits im Post drüber beschrieben. Genau lautet diese (Ablaufverfolgung):

    std::vector<float, std::allocator<float> >::push_back(this = 0x0, __x = @0x29f3f8: 0.0549999997) C:/Program Files (x86)/Dev-Cpp/MinGW64/lib/gcc/x86_64-w64-mingw32/4.9.2/include/c++/bits/stl_vector.h 915

    Plate::setField(this = 0x29f40c, wave = 0, field = 0, density = 0.0549999997) main_template.cpp 75



  • Den Code kann ich jetzt ja immer noch nicht selbst compilieren um den Fehler nachzustellen. In der main Funktion wird aber schon vorher mal set_plate mit der richten Größe aufgerufen?



  • Genau, Instanzen von Plate wird erzeugt.

    Plate P[plates_num];
    

    Das Ding ist, dass der Code vorher lief, bevor ich die float Arrays durch Vektoren ersetzt habe.

    D.h. im Grunde bräuchte ich nur eine Hilfe, wie ich richtig mit mehrdimensionalen Vektoren arbeite (der Code an sich ist korrekt). Mit eindimensionalen Vektoren habe ich wie gesagt kein Problem. Falls Ihr mir das hier nicht erklären könnt und Ihr mir stattdessen einen guten Link zu einer Eklärung geben könnt, wäre ich Euch auch dankbar. Ich finde leider nur etwas über eindimensionale Probleme und bei meinen Versuch dieses auf mehrdimensionale Vektoren anzuwenden scheitere ich 😞



  • Die Funktion push_back wird für einen nicht existierenden Vector aufgerufen (this ist ein Nullpointer). Das ist plausibel, denn wenn du absorb.resize(wave) aufrufst, ist absorb[wave] natürlich ungültig.



  • tillt schrieb:

    Genau, Instanzen von Plate wird erzeugt.

    Plate P[plates_num];
    

    Und wird jetzt set_plate irgendwo aufgerufen? Dadurch, dass du ein Array anlegst passiert das jedenfalls nicht.

    tillt schrieb:

    Das Ding ist, dass der Code vorher lief, bevor ich die float Arrays durch Vektoren ersetzt habe.

    Das ist leider keine Garantie dafür, dass der Code vorher fehlerfrei war. Vielleicht hast du auch wild irgendwas im Speicher überschrieben und es war einfach Glück, dass es nicht abgestürzt ist.

    Zweidimensionale Arrays mit vector funktionieren genauso wie eindimensionale. Wenn du endlich mal ein vollständiges (für das Problem irrelevante Teile weglassen) und compilierbares Codebeispiel zu deinem Problem lieferst, dann findet einer der Experten hier den Fehler sicher in Rekordzeit.


  • Mod

    Man sollte noch erwähnen, dass ein verschachtelter Vector nicht der Datenstruktur entspricht, die man im allgemeinen als 2D-Array bezeichnet. Ein 2D-Array wäre offensichtlich ein Array von Arrays, kein Vector von Vectoren. Oder auch ein Vector von Arrays, der auch das gleiche Layout hätte wie ein Array von Arrays.

    Dieses Missverständnis scheint, neben allgemeiner Unkenntnis von Vectoren, eine der Ursachen des Problems zu sein. Vectoren haben eben die Eigenschaft flexibler Größe, Arrays nicht. Was dazu führt, dass ein leerer Vector wirklich leer ist. Da ist absolut nichts drin, nicht einmal leerer Platz.



  • Vielen Dank für eure Tipps! Ich habe jetzt ein Minimalbeispiel meines Problems erstellt und hoffe ihr könnt mir so besser meine Fehler aufzeigen.

    #include <cstdlib>
    #include <stdlib.h>
    #include <stdio.h>
    #include <iostream>
    #include <math.h>
    #include <vector>
    
    using namespace std;
    
    class testclass	{
    
      public:
    
            vector<vector<float> > matrix;
    
    		void set_matrix(int rows, int cols);
    		void setField(int row, int col, float value);
    		float getField(int row, int col);
    
    };
    
    void testclass::set_matrix(int rows, int cols)	{
      matrix.reserve(rows);
      for (int i = 0; i < rows; ++i)	{	matrix[i].reserve(cols);	}
    };
    
    void testclass::setField(int row, int col, float value)	{
    	// okay, hier wird erstmal col nicht benötigt
    	matrix[row].push_back(value);
    };
    
    float testclass::getField(int row, int col)	{
    	return	matrix[row][col];
    };
    
    int main(int argc, char *argv[])	{
    
    	int copys = 38;
    	testclass P[copys];
    	int rows=2;
    	int cols=96;
    
    	for (int j=0; j < copys; j++)	{	P[j].set_matrix(rows, cols);		}
    
    	for ( int j = 0; j < copys; j++)	{
    		for ( int i = 0; i < rows; i++)	{
    			P[j].setField(i, 0, 5.00);
    			P[j].getField(i, 0);
    		}
    	}
    }
    

    Grob gesagt möchte ich Vektoren von float Vektoren in einer Klasse während des Hauptprogramms setzen und lesen. Wobei die Größe beim Erstellen der Klasseninstanzen noch nicht bekannt ist.


  • Mod

    Hast du irgendeine der Antworten in diesem Thread gelesen? Du machst doch immer noch reserve, wo resize angebracht wäre. Außerdem traf meine Spekulation weiter oben voll ins Schwarze: Ein vector<vector<float>> ist keine gute Datenstruktur für eine mathematische Matrix. Besser wäre hier einfach ein ganz normaler vector<float>. Als Anpassung deines Programm ginge das so (ungetestet gegen Tippfehler und sonstiges):

    class testclass {
    
      public:
    
            vector<float> matrix;
            unsigned num_rows, num_cols;
            void set_matrix(int rows, int cols);
            void setField(int row, int col, float value);
            float getField(int row, int col);
    
    };
    
    void testclass::set_matrix(int rows, int cols)  {
      num_rows = rows; num_cols = cols;
      matrix.resize(num_rows * num_cols);
    };
    
    void testclass::setField(int row, int col, float value) {
        // Natürlich wird hier col benötigt. Fällt dir das nicht als Logikfehler beim Programmieren auf, dass das nicht sein kann, dass du ein Matrixelement ohne Spaltenindex adressieren willst?
        matrix[row * num_cols + col] = value;
    };
    
    float testclass::getField(int row, int col) {
        return  matrix[row * num_cols + col];
    };
    


  • Danke SeppJ,

    das eindimsionale Beispiel von dir läuft gut. Auch wenn dies die bessere Lösung ist, möchte ich gerne verstehen, wie ich es im Falle eines vector < vector < float> > lösen kann.
    In meinen Beispielcode hatte ich auch schon reserve durch resize ausgetauscht (sorry! Komischerweise hält das Programm in der letzten Schleife bei mehr Elementen durch (Programmabsturz), wenn ich reserve statt resize benutze!?).
    Ich denke mein Fehler liegt darin, dass ich die "cols" auch "resizen" möchte...

    #include <cstdlib>
    #include <stdlib.h>
    #include <stdio.h>
    #include <iostream>
    #include <math.h>
    #include <vector>
    
    using namespace std;
    
    class testclass	{
    
    	public:
            int col;
            vector<vector<float> > matrix;
    
    		void set_matrix(int rows, int cols);
    		void setField(int row, int col, float value);
    		float getField(int row, int col);
    
    };
    
    void testclass::set_matrix(int rows, int cols)	{
      matrix.resize(rows);
      for (int i = 0; i < rows; ++i)	{	matrix[i].resize(cols);	}
    };
    
    void testclass::setField(int row, int col, float density)	{
    	// okay, hier wird erstmal col nicht benötigt - da ich ja mit push_back nur in die Reihe direkt ans Ende schreibe!
    	//matrix[row].push_back(density);
    	matrix[row][col] = density;
    };
    
    float testclass::getField(int row, int col)	{
    	return	matrix[row][col];
    };
    
    int main(int argc, char *argv[])	{
    
    	int copys = 38;
    	testclass P[copys];
    	int rows = 2;
    	int cols = 96;
    	int num = 0;
    
    	for (int j=0; j < copys; j++)	{	P[j].set_matrix(rows, cols);		}
    
    	for ( int j = 0; j < copys; j++)	{
    		for ( int i = 0; i < cols; i++)	{
                for ( int k = 0; k < rows; k++)	{
                    P[j].setField(i, k, num);
                    num++;  cout << "\n" << P[j].getField(i, k);
                }
            }
        }
    }
    

    Aber wenn ich nur matrix.resize(rows) anwende bekomme ich nach einigen Elementen einen Programmabbruch, weshalb ich davon ausgehe, dass es zu Speicherüberschneidungen der einzelnen Reihen kommt, da nicht genügend Speicher für die Spaltenelemente matrix[row] = c1, ..., cn vorhanden ist.
    Aber wie kann ich die "gesamte" Größe einer Reihe richtig setzen? Mit matrix.resize(row*cols) geht es auch nicht.
    Bitte entschuldige, wenn ich immer noch Denkfehler mache!



  • tillt schrieb:

    Aber wenn ich nur matrix.resize(rows) anwende bekomme ich nach einigen Elementen einen Programmabbruch, weshalb ich davon ausgehe, dass es zu Speicherüberschneidungen der einzelnen Reihen kommt, da nicht genügend Speicher für die Spaltenelemente matrix[row] = c1, ..., cn vorhanden ist.
    Aber wie kann ich die "gesamte" Größe einer Reihe richtig setzen? Mit matrix.resize(row*cols) geht es auch nicht.
    Bitte entschuldige, wenn ich immer noch Denkfehler mache!

    "Wenn ich Hufe höre, denke ich an Pferde."

    Warum testest Du nicht erstmal, ob Deine Zugriffe alle innerhalb der Grenzen liegen?
    Ein einfaches if... genügt. Stattdessen ergibst Du dich in wilden Vermutungen.



  • Du hast cols und rows vertauscht. Wenn du die Klasse unverändert lässt müsste die Schleife so aussehen:

    for (int i = 0; i < rows; i++) {
      for (int k = 0; k < cols; k++) {
        P[j].setField(i, k, num);
        num++;  cout << "\n" << P[j].getField(i, k);
      }
    }
    


  • Okay 😃
    Vielen Dank euch allen - ich denke ich habe jetzt alle (meine 🤡 ) Fehler eliminiert.


Log in to reply