2d-array im header anmelden und später spezifizieren



  • Hallo, ich bin neu bei c++ und muss leider schon bei so einfach Dingen wie 2d-arrays Euren profi-Rat in Anspruch nehmen, da alle Array-bezogenen Themen wie folgt aussehen:

    void main() {
      int** bla = ...
    }
    

    Ich habe gelesen dass vector hilfreich sein soll, weil man sich nicht um die Speicherfreigabe kümmern muss.

    vector<vector<int>, 5> myArray(6);
    

    Was ich nicht gefunden habe und was mich wirklich wundert und auch ein wenig nervt:
    Was ist wenn ich das array lediglich im Header-File für eine Klasse anmelden möchte und erst im Konstruktor in der cpp-Datei die größe festlegen möchte?

    Also ungefähr so:
    meineKlasse.h

    vector<vector<myOtherClass>> myArray;
    

    meineKlasse.cpp

    myArray = new ?
    

    Hat da jemand Ahnung wie das geht?
    Vielen Dank schonmal.



  • Dieser Thread wurde von Moderator/in Martin Richter aus dem Forum MFC (Visual C++) in das Forum C++ (alle ISO-Standards) verschoben.

    Im Zweifelsfall bitte auch folgende Hinweise beachten:
    C/C++ Forum :: FAQ - Sonstiges :: Wohin mit meiner Frage?

    Dieses Posting wurde automatisch erzeugt.


  • Mod

    Zwei wichtige Punkte:
    1. Sowohl Doppelzeiger (oder genauer: das, worauf diese zeigen können) als auch vector<vector> sind keine 2D-Arrays. Das sind eher Listen von Arrays. Der Unterschied:
    2D-Array (2x3) im Speicher:

    -------------------------------------
    |(0,0)|(0,1)|(0,2)|(1,0)|(1,1)|(1,2)|
    -------------------------------------
    

    Also alles direkt beieinander.
    Zeiger auf Array von Zeigern auf Arrays:

    ---------------
    |anfangszeiger|
    ---------------
           | Zeigt auf Array von Zeigern
           v
    -----------------------                                   ---------------------
    | Zeiger 0 | Zeiger 1 |---------------------------------->| 0 | 1 | 2 | 3 | 4 |
    -----------------------    zeigt auf ein anderes Array    ---------------------
         | zeigt auf ein Array              
         V                               Die Arrays auf die gezeigt wird, müssen
    -------------                        nicht gleich groß sein
    | 0 | 1 | 2 |
    -------------
    

    vector<vector> ist ähnlich.

    Die Flexibilität, die man bei vector<vector> hat, geht auf Kosten der Laufzeit im Vergleich zu echten 2D-Arrays.

    Vector ist übrigens immer der manuellen Speicherverwaltung vorzuziehen. Das ist auch Punkt 2:

    2. Benutz niemals new!
    Es muss nicht immer vector sein (es gibt so viele andere Container), aber ein ungekapseltes new ist immer falsch und wer dir das beigebracht hat, gehört dafür getreten.

    Wie nun 2D-Arrays?
    Es gibt viele Varianten, je nachdem, was du über das Array weißt. Gängige Möglichkeiten:

    Du kennst X und Y Größe bereits zur Compilezeit (d.h. während du programmierst), z.B. Größe eines Schachbretts oder ähnliches:

    array<array<datentyp, groesse_1>, groesse_2> dein_2D_array;
    

    Also einfach ein Array von Arrays. (In C++ ist auch fast immer std::array einem rohen Array vorzuziehen!)

    Du kennst eine der Größen bereits zur Compilezeit (z.B du weißt, jeder Datensatz hat 4 Einträge, aber du weißt nicht wie viele Datensätze kommen):

    vector<array<datentyp, 4> > dein_semi_flexibles_2D_array;
    

    Du weißt nix, außer dass es irgendwie "rechteckig" ist, also X*Y-Einträge (nicht so wie bei vector<vector>, wo jedes innere Array eine andere Größe haben kann):

    vector<datentyp> dein_voll_flexibles_2D_array;
    

    Moment! Einfach ein vector? Wie geht das? Ganz einfach: Man will ja Alle Einträge schön an einem Stück, genau das macht ein vector. Aber wie adressiert man da drin mit 2 Koordinaten? Antwort: Man rechnet sich selber aus, welchen Index man braucht:

    Index(x,y) = x * y_laenge + y;
    

    Genau diesen Code würde der Compiler auch erzeugen, wenn man ein statisches (oder semi-flexibles) 2D-Array hat, um letztlich an die Einträge zu kommen. Schließlich können Computer nicht zaubern und was der Compiler kann, kann man selber auch machen. Da wir in C++ sind, können wir das alles in eine Klasse packen, damit es schön zu benutzen ist:
    (Hier im Editor programmiert und ungetestet, enthält wahrscheinlich Schreibfehler)

    class IntArray2D
    {
      vector<int> data;
      size_t length_y;
    public:
      IntArray2D(size_t length_x, size_t length_y): data(length_x * length_y), length_y(length_y) { }
      int& get(size_t x_coord, y_coord) { return data[x_coord * length_y + y_coord]; }
    };
    
    int main()
    {
      IntArray2D my_array(2,3);
      my_array.get(1,1) = 5;
    }
    

    Da dran kann man noch sehr viel besser machen. Ein paar Anregungen:
    -Wir wollen auch einen const-Zugriff
    -Wir wollen die Größe ändern können
    -get ist ein doofer Name. Zu viel zu schreiben. Operatorüberladung nutzen. (Leider ist es recht schwierig, wenn man Zugriffe in der Form my_array[1][1] erreichen möchte. Aber man kann ganz leicht my_array(1,1) erreichen.)
    -Die Festlegung auf int ist doof, also ein Template daraus machen
    -Das Ganze möglichst STL-konform gestalten (das ist viel Arbeit)
    Wenn man all dies tut, dann hat man die perfekte 2D-Array-Klasse, die man sein Leben lang so benutzen kann.


Anmelden zum Antworten