Dynamisches Array/Matrix Speicher freigeben (delete)



  • Hallo,

    zu einem dynamisch angelegten Array und einer Matrix möchte habe ich wie folgt Speicherplatz reserviert:

    // x,m,n sind vom Typ int und sind Benutzereingaben
    double* vektor1=new double[x];
    double** matrix1=new double* [m]; 
    for(int i=0;i<n;i++)
      {
        matrix1[i]=new double[n];
      }
    // Im Programm wird dann damit gerechnet etc.
    

    Am Ende möchte ich den Speicherplatz wieder freigeben:

    delete[] vektor1;  
    for(int i=0;i<m;i++)
      {
        delete[] matrix1[i];
      }
    delete[] matrix1;
    

    Es gibt zwar keinen Compiler-/Laufzeitfehler, aber so ganz zu funktionieren scheint es trotzdem nicht, zumindest wenn ich mir Vektor und Matrix nach dem Löschvorgang ausgeben lasse. Da sollten doch dann entweder Nullen oder "komische" Werte (z.B. 1.39829e-293) drin stehen, nicht? Bei meinem Vektor wird z.B. nur das erste Element gelöscht.

    Bitte Vektor nicht mit "vector" verwechseln, dieser Typ soll hier nicht verwendet werden.

    Danke für eure Hilfe!



  • svloga schrieb:

    Da sollten doch dann entweder Nullen oder "komische" Werte (z.B. 1.39829e-293) drin stehen, nicht?

    Nein, wie kommst du darauf?



  • svloga schrieb:

    Da sollten doch dann entweder Nullen oder "komische" Werte (z.B. 1.39829e-293) drin stehen, nicht?

    Wer sollte sich denn die unnütze Arbeit machen, ungültigen Speicher extra mit Nullen oder komischen Werten zu überschreiben?
    Du hast für jedes new[] ein delete[] (in der richtigen Reihenfolge). Passt schon.



  • Einige Runtimes überschrieben im Debug(!)-Modus den Speicher nach der Freigabe:
    http://stackoverflow.com/a/127404

    Der Normalfall, besonders bei Release-Builds ist allerdings nichts mit dem freigegebenen Speicher zu machen. D.h. es stehen danach noch die selben Werte wie vorher drin,
    oder du bekommst eine Zugriffsverletzung wenn die Speicherseite danach aus irgendeinem Grund nicht mehr in den virtuellen Adressraum des Prozesses gemappt ist.

    Finnegan

    P.S.: Wenn du Wert auf Effizienz legst ist dieser Pointer-auf-Pointer-Ansatz für die Matrix nicht unbedingt die beste Wahl:
    Wie auch bei einem std::vector<std::vector<>> liegen dabei die Zeilen der Matrix meistens irgendwo wild im Speicher verteilt.



  • Danke für eure Reaktionen.

    Das mit den Werten nach dem Löschen war nur eine grob fahrlässige Vermutung meinerseits 😃
    Deswegen war mein Gedanke auch, dass es wohl nicht funktioniert hat. Hatte z.B. nicht erwartet, dass da z.T. noch die gleichen Werte wie vorher drin stehen können.

    Aber jetzt weiß ich ja Bescheid.

    // Jo das ist mir auch aufgefallen, die Spaltenelemente pro Zeile sind noch ganz "ordentlich" hintereinander, aber die Zeilen ansich sind wild verteilt.



  • svloga schrieb:

    Das mit den Werten nach dem Löschen war nur eine grob fahrlässige Vermutung meinerseits 😃

    War ja auch nicht ganz falsch, siehe Finnegan.



  • Finnegan, was wäre denn deine Idee um hier die Effizienz zu steigern?

    Dachte vector sei schon super optimiert...



  • Halt ein Vector/array und Indices umrechnen.



  • Sewing schrieb:

    Finnegan, was wäre denn deine Idee um hier die Effizienz zu steigern?

    Siehe Jockelx' Antwort.
    Zusätzlich ist es nicht verkehrt die Speicherverwaltung einem Container der
    Standardbibliothek zu überlassen ( std::vector ). Für eine dynamische Matrix
    (Dimensionen erst zur Laufzeit bekannt, da User-Eingabe) wird sich der daraus
    erzeugte Maschinencode wahrscheinlich nicht von der "manuellen" Variante unterscheiden.

    Ein Ansatz dafür könnte z.B. so aussehen:

    #include <iostream>
    #include <vector>
    
    template <typename T>
    class matrix
    {
        public:
            matrix(std::size_t m, std::size_t n)
            : rows(m), cols(n), elements(m * n)
            {
                assert(m * n > 0);
            }
    
            std::size_t getRows() const
            {
                return rows;
            }
    
            std::size_t getCols() const
            {
                return cols;
            }
    
            T& operator()(std::size_t i, std::size_t j)
            {
                assert(i < rows && j < cols);
                return elements[i * cols + j];
            }
    
            const T& operator()(std::size_t i, std::size_t j) const
            {
                assert(i < rows && j < cols);
                return elements[i * cols + j];        
            }
    
        private:
            std::size_t rows;
            std::size_t cols;
            std::vector<T> elements;
    };
    
    template <typename T>
    std::ostream& operator<<(std::ostream& out, const matrix<T>& m)
    {
        out << "{ ";
        for (std::size_t i = 0; i < m.getRows(); ++i)
        {
            out << ((i > 0) ? ", [" : "[");
            for (std::size_t j = 0; j < m.getCols(); ++j)
                out << ((j > 0) ? ", " : " ") << m(i, j);
            out << " ]";
        }
        out << " }";
        return out;
    }
    
    int main()
    {
        matrix<double> m{ 3, 3 };
    
        std::cout << m << std::endl;
    
        m(0, 0) = 1;
        m(1, 1) = 1;
        m(2, 2) = 1;
    
        std::cout << m(0, 0) << std::endl;    
        std::cout << m << std::endl;
    
        return 0;
    }
    

    Das ist zumindest die Art und Weise wie ich heutzutage eine solche Matrix implementieren würde.


Log in to reply