Wo werden die Daten gespeichert (heap, stack)?



  • Hallo Forum,
    ich würde gerne wissen, wo die Daten bei der Erstellung der Matrix gespeichert werden (heap od. stack) und ob diese Struktur auch gängiger Programmier-Stil ist. Oder sollte man den Vector nicht auch als Pointer definieren?

    class Matrix {
      private:
        int rows, cols;
        vector<vector<double>> data;
    }
    
    // Konstruktor
    Matrix::Matrix(int r, int c) {
      rows = r;
      cols = c;
      data.resize(rows, std::vector<double>(cols));     //dimensionieren
      ...
    } 
    
    // Aufruf zur Erstellung einer Matrix
    Matrix* pMx = new Matrix(4, 4);
    


  • Ein std::vector hat auf dem Stack eine konstante Größe (wie jeder Typ) und fordert für seine Daten (je nach Größe) Speicher aus dem Freispeicher an. Ein vector besteht aus einem Pointer auf die Daten, einer Größe und einer Kapazität (oder irgendwas in der Art, 3 Zeiger gingen auch, wie das genau implementiert ist, haben die Standardbibliothekautoren entschieden).

    Insbesondere erfordert ein vector<vector<double>> beim Zugriff auf ein Element also 2x eine Pointer-Dereferenzierung - und vor allem ist bei dieser Datenstruktur nicht sichergestellt, dass alle Zeilen gleich viel Spalten haben. Es macht meistens mehr Sinn, die Matrix mit einem std::vector<T> zu implementieren. (dann muss man für den Zugriff auf ein Element halt multiplizieren)

    // Aufruf zur Erstellung einer Matrix
    Matrix* pMx = new Matrix(4, 4);
    

    Besser:

    // Aufruf zur Erstellung einer Matrix
    Matrix Mx(4, 4);
    

    (oder, wenn unbedingt ein Pointer benötigt wird, auto pMx = std::make_unique<Matrix>(4, 4); verwenden - aber dann solltest du auch einen Grund für den Pointer haben).


  • Mod

    Die Diskussion hatten wir vor kurzem quasi schon einmal:
    https://www.c-plusplus.net/forum/topic/354514/pointer-wegen-möglichen-stackoverflow

    Kurzfassung: Es ist weder nötig noch gut, sich als Anwender um die internen Details anderer Datenstrukturen zu kümmern. Das machen diese Datenstrukturen ja schon selber und wissen sicher besser, was gut ist.



  • @wob sagte in Wo werden die Daten gespeichert (heap, stack)?:

    (oder, wenn unbedingt ein Pointer benötigt wird, auto pMx = std::make_unique<Matrix>(4, 4); verwenden - aber dann solltest du auch einen Grund für den Pointer haben).

    Nun ich möchte keine Pointer verwenden, wenn sie nicht notwendig sind. Aber wann hat man den Grund oder muss einen Pointer verwenden?



  • @SeppJ Ersuche um Begriffserklärung: Was sind VLA, C-VLA, Blob?


  • Mod

    @znieh99 sagte in Wo werden die Daten gespeichert (heap, stack)?:

    @SeppJ Ersuche um Begriffserklärung: Was sind VLA, C-VLA, Blob?

    Unwichtig, denn die Antwort gilt allgemein:

    @znieh99 sagte in Wo werden die Daten gespeichert (heap, stack)?:

    Nun ich möchte keine Pointer verwenden, wenn sie nicht notwendig sind. Aber wann hat man den Grund oder muss einen Pointer verwenden?

    1. Wenn du eigene komplexe Datenstrukturen aufbaust. Pointer sind nötig um die Beziehungen der Daten untereinander ausdrücken
    2. Wenn du etwas schreibst, das direkt eine dynamische Ressource hält. Pointer sind nötig um auf die Ressource zu verweisen
    3. Du hast die Anforderung, dass ein Parameter sich wie eine Referenz verhält, aber auch auf "Nichts" verweisen kann. Der Pointer ist nötig, weil Referenzen nur auf gültige Objekte verweisen können
    4. Du musst eine C-Schnittstelle bedienen. Pointer sind nötig, weil C keine Referenzen kennt.

    Nummer 3 ist eine recht spezielle Notwendigkeit, und wenn du das im großen Stil hast, dann ist das eher etwas für einen Meta-Typen wie std::optional.

    Nummer 1 kann schon vorkommen, aber wenn du solche Fragen stellst, dann haben deine Programme wahrscheinlich noch lange nicht die Komplexität, wo die fertig bereitgestellten Datenstrukturen nicht ausreichen.

    Nummer 2 denken viele Anfänger ganz oft, dass sie diesen Fall hätten, aber ist eigentlich immer Unwissen über die Möglichkeiten der Standardbibliothek. Indirekt hält man andauernd dynamische Ressourcen, aber eigentlich immer wird die Verantwortung dafür an einen Spezialisten delegiert, der sich direkt darum kümmert.

    Nummer 4 kommt leider manchmal vor. Dann musst du eben die Adressen von deinen C++-Objekten übergeben, und sicher sein, dass diese den Anforderungen der Schnittstelle genügen.

    Merke: In den Fällen 1, 3, und 4 sind das nicht-besitzende Pointer. Reine Verweise, ohne Verantwortung für Ressourcen. Die eigentliche Ressourcenverwaltung machen Spezialisten aus Fall 2, die man - wie erklärt - auch nur selten selber schreibt. Ein new kommt daher in C++ so gut wie nie vor, und wenn dann nur, um die Verantwortung für die Speicherressource sofort abzutreten.

    Oft sieht man die Pointer nicht einmal. Besonders die Fälle 1, 3, 4 haben oft Objekte, die sich zwar wie eine Pointer verhalten (oder direkt intern einen Pointer als Member haben), aber technisch gesehen selber gar keine Pointer sind. Und dann kann es dir als Nutzer auch egal sein, wie die das intern machen.



  • @wob sagte in Wo werden die Daten gespeichert (heap, stack)?:

    Besser:
    // Aufruf zur Erstellung einer Matrix
    Matrix Mx(4, 4);

    Obwohl dies ein dynamisches Objekt ist brauche ich keinen Pointer!?!


  • Mod

    Nein! Den hat doch der Vector.



  • @SeppJ Ok, dann brauche ich das auch nicht löschen?


  • Mod

    Verantwortlich für die Freigabe einer Ressource ist derjenige, der sie angefordert hat, oder an den die Verantwortung übergeben wurde. Hast du irgendwo eine Ressource angefordert? Tatsächlich ja, mit dem new in deinem ersten Beitrag, aber wob hat dir ja direkt erklärt, dass du das besser sein lässt. Hat dir der Vector irgendwelche Ressourcen übergeben? Nein. Also was willst du überhaupt freigeben? Du hast ja nichts (wenn du den Quatsch mit dem new sein lässt).

    Der Vector kümmert sich schon alleine um alles.



  • @SeppJ Es ist eine Klasse "Matrix" die einen Vector beinhaltet, die ich jetzt aber ohne new erstelle.


  • Mod

    Ja, das sehe ich und das ist doch genau das, was ich beschrieben habe. Was willst du da löschen? Du hast nichts zu löschen. Wie kommst du überhaupt darauf? Vergiss einfach alles über new, Pointern, und Co. Brauchst du erst einmal nicht, und wenn du doch mal so weit bist, dass du es brauchst, wirst du es auch selber wissen.



  • @SeppJ Ok, danke!


Anmelden zum Antworten