Probleme mit dynamischen Arrays (malloc und free)



  • Du solltest Objekte bei Funktionsaufrufen per Referenz übergeben, nicht per Value. Wenn sie in der Funktion nicht verändert werden auch gern als const-Reference. Ansonsten wird jeder Parameter als Kopie erstellt, was bei std::vector schnell teuer werden kann.

    Ansonsten gibt´s hier im Forum eine fertige Implementation eines 2D-Arrays, vllt hilft dir das ja weiter.



  • @Rav1642 sagte in Probleme mit dynamischen Arrays (malloc und free):

    Ich habe die Berechnung der Determinante außerhalb der Klasse.

    Warum?

    Sollte ich das mit anderen Methoden auch so handhaben?

    Wenn du dir die Frage von oben beantwortest, dann weisst du doch auch, ob es bei anderen Funktionen ebenfalls sinnvoll ist.
    Allgemein wirst du aber mit freien nicht-friend Funktionen viel Zustimmung kriegen.
    Ich persönlich hätte aber auch mit einer const member function "determinant" kein Problem, aber wie gesagt, eine freie Funktion wird tendenziell bevorzugt
    (weil Meyers das sagt und man immer gut beraten ist, die Tipps zu beherzigen)


  • Mod

    @Rav1642 sagte in Probleme mit dynamischen Arrays (malloc und free):

    Gut, danke. Jetzt möchte ich ja nur verschiedenste Anwendungen aus dem Bereich der linearen Algebra umsetzen. Ich habe aktuell gar nicht vor, in die Tiefen der Speicherverwaltung vorzudringen. Für meine Zwecke reicht nun in der neuesten Version auch ein eindimensionaler std::vector<double> für die Elemente der Matrix.

    Hurra! Gute Entscheidung. Zusatztipp: Du wirst quasi nie eigene Speicherverwaltung benötigen, außer für Hausaufgaben zur Speicherverwaltung. Das Thema ist gelöst und jede Eigenlösung kann nur schlechter sein.

    @john-0 sagte in Probleme mit dynamischen Arrays (malloc und free):
    Ich habe also etwas an meiner Matrix-Klasse gefeilt und möchte nochmal auf die Funktionalität zurück.
    Ich habe die Berechnung der Determinante außerhalb der Klasse. Sollte ich das mit anderen Methoden auch so handhaben?

    Kann man so pauschal nicht sagen. Ist eher eine philosophische Trennung, ob du ausdrücken möchtest, dass etwas eine Eigenschaft einer Matrix ist, oder etwas, das man mit einer Matrix tut. Beispielsweise würde ich ihre Transponierte eher als Eigenschaft einer Matrix ansehen.

    In dem Sinne finde ich Bezeichner wie getSize als Memberfunktion eher ungünstig. size wäre da verständlicher. Es ist die Größe der Matrix, es holt sie nicht. Wenn du Memberfunktionen Namen gibst, als seien sie Eigenschaften von einem Ding, dann liest sich dein Programm am Ende fast so wie ein englischer Text und man findet Logikfehler schon alleine dadurch, dass der Text keinen Sinn macht.

    Hier ist die Matrix.h:

    #pragma once
    #include <vector>
    
    class Matrix {
    private:
    	std::vector<double> values;
    	int r; // number of rows
    	int c; // number of columns
    	int size;
    	double lowestVal;
    	double highestVal;
    
    public:
    	// constructor
    	Matrix(int rows, std::vector<double> vals);
    
    	// special methods
    	void print(int precision);
    	Matrix submatrix(int deletedRow, int deletedColumn);
    
    	// standard setter
    	void setValue(int row, int column, double newValue);
    	void setValue(int pos, double newValue);
    
    	// standard getter
    	double getValue(int row, int column);
    	double getValue(int pos);
    	double getLowestVal(); // lowest value
    	double getHighestVal(); // highest value
    	int getRows();
    	int getColumns();
    	int getSize(); // equivalent to rows * columns
    
    	// operator overloading
    	Matrix operator- (); //unary
    	friend Matrix operator+ (Matrix m, Matrix n);
    	friend Matrix operator- (Matrix m, Matrix n);
    	friend Matrix operator* (Matrix m, Matrix n);
    	
    	// destructor
    	~Matrix();
    };
    
    double determinant(Matrix m);
    

    Vielen Dank euch! 🙂

    Das sieht schon gar nicht mehr schlecht aus. Kleinigkeiten neben dem das @DocShoe gesagt hat:

    • size sieht redundant aus mit r und c und values.size()
    • Destruktor ist unnnötig. Googel nach 'Rule of 0' für Hintergrundwissen. Oder ohne Hintergrundwissen: Die Funktion ist doch sicher leer bei dir. Dann lass sie doch weg.
    • Hältst du wirklich die ganze Zeit lowestVal und highestVal aktuell? Klingt umständlich für wenig Mehrwert. Oder du vergisst etwas.
    • Eine Print-Funktion in C++ macht man eigentlich anders. Das hat aber jetzt erst einmal nicht speziell mit Matrizen zu tun, und mit deiner jetzigen Lösung kann man auch gut leben. Aber behalte mal im Hinterkopf, später zu lernen, wie man in C++ Ausgabefunktionen für Klassen baut.
    • Guck dir auch das Thema 'const-correctness' an. So etwas wie getSize() sollte const sein. Das ist auch etwas, was du jetzt wahrscheinlich nicht unbedingt machen musst, aber du könntest später Probleme bekommen, wenn du es nicht tust. Und wenn du dann Probleme bekommst, musst du gleich sehr viel ändern.


  • @Rav1642 sagte in Probleme mit dynamischen Arrays (malloc und free):

    Na, du hast ja viel Vertrauen in mich. 😃
    Soweit ich weiß, reserviert ein Allocator Speicher:

    std::allocator<double> alloc;
    double *d = alloc.allocate(10);
    

    So nutzt man einen Allocator eher weniger. Das Thema zu diskutieren ergibt keinen Sinn, solange Du nicht weißt wie man die rule of five correct umsetzt.



  • @john-0 sagte in Probleme mit dynamischen Arrays (malloc und free):

    solange Du nicht weißt wie man die rule of five correct umsetzt.

    wtf? @Rav1642's class hat nur simpel copyable typen als member. Rule of 0 ftw.

    @Rav1642 tu den d-tor weg. das bringt nix.



  • @Swordfish sagte in Probleme mit dynamischen Arrays (malloc und free):

    wtf? @Rav1642's class hat nur simpel copyable typen als member. Rule of 0 ftw.

    Einfach nicht Sinn entstellend zitieren, und dann ist schon klar, dass das so korrekt ist.



  • @john-0 was ist daran sinnentstellend!?



  • @Swordfish sagte in Probleme mit dynamischen Arrays (malloc und free):

    @john-0 was ist daran sinnentstellend!?

    Du hast das Zitat über meiner Antwort weggelassen. Mit dem Zitat von Rav1642 ist auch klar, weshalb ich das geschrieben habe.



  • @DocShoe sagte in Probleme mit dynamischen Arrays (malloc und free):

    Du solltest Objekte bei Funktionsaufrufen per Referenz übergeben, nicht per Value. Wenn sie in der Funktion nicht verändert werden auch gern als const-Reference.

    Das ist die Erklärung, die ich gebraucht habe, danke. Ich werde es ändern! 🙂

    @Jockelx sagte in Probleme mit dynamischen Arrays (malloc und free):

    Ich habe die Berechnung der Determinante außerhalb der Klasse.

    Warum?

    Sollte ich das mit anderen Methoden auch so handhaben?

    Wenn du dir die Frage von oben beantwortest, dann weisst du doch auch, ob es bei anderen Funktionen ebenfalls sinnvoll ist.

    Dass ich Determinante auslagerte, liegt daran, dass ich hier im Forum herausfinden wollte, ob die Trennung der Funktionalität so gemeint war.

    @SeppJ sagte in Probleme mit dynamischen Arrays (malloc und free):

    In dem Sinne finde ich Bezeichner wie getSize als Memberfunktion eher ungünstig. size wäre da verständlicher.

    Dass das angesprochen würde, habe ich mir gedacht, da size() ja so öfter zu finden ist. Ich sag mal so, das ist eine schlechte Lösung gewesen, das dämmerte mir schon. Ich werde deinen Rat selbstverständlich umsetzen, danke sehr. 🙂

    @SeppJ sagte in Probleme mit dynamischen Arrays (malloc und free):

    Destruktor ist unnnötig. Googel nach 'Rule of 0' für Hintergrundwissen. Oder ohne Hintergrundwissen: Die Funktion ist doch sicher leer bei dir. Dann lass sie doch weg.

    Damit liegst du sehr richtig. Als ich den Destruktor erstellte, war hier noch free() drin verarbeitet. Das habe ich entsorgt und der Destruktor blieb verkümmert zurück. Klar, den brauche ich nicht, aber so ist sie, die Evolution. 😅

    Bzgl. Rule of Five:
    Mein Cpp-Buch vom Author Jürgen Wolf besagt grob vier Punkte:

    • fertige Container verwenden (in meinem Fall den std::vector<double>)
    • Smart Pointer nutzen (hierzu werde ich mich in Kürze genauer einlesen)
    • durch Smart Pointer sind delete und delete[] unnötig (steigende Konsistenz des Speichers)
    • keine Regel der Rule of Five definieren, sondern das dem Compiler überlassen (das verstehe ich nicht, da ich ja mindestens den Zuweisungsoperator brauche, nicht?)

    Ich danke auf jeden Fall für den Verweis auf solche Faustregeln. Es ist sicher gut, solche zu verstehen, um sie sinnvoll anzuwenden. Ich stehe grad allerdings zwischen den Fronten von Rule of Zero und Rule of Five, hier habe ich Nachholbedarf. 🤓

    @john-0 sagte in Probleme mit dynamischen Arrays (malloc und free):

    solange Du nicht weißt wie man die rule of five correct umsetzt.

    Diese Regel habe ich mir gestern bereits angeschaut, aber erkenne den Sinn nicht. Wahrscheinlich, weil ich gar keine Notwenigkeit erkenne.
    Es gibt:

    • Kopierkonstruktor (den ich nicht nachvollziehe, da man ja statt einer Referenz die Kopie direkt übergeben könnte, statt aus der Referenz eine Kopie zu machen),
    • Destruktor (der zum "Aufräumen" belegter Ressourcen wichtig ist),
    • Zuweisungsoperator (der ja in den allermeisten Programmen sowieso verwendet wird),
    • Verschiebekonstruktor (der in Fällen, wo Kopieren keine Option ist, sinnvoll zu sein scheint; einen Nutzen sehe ich persönlich für mein Programm nicht.
    • Verschiebezuweisung (mein schlaues Buch kennt das, ich noch nicht)

    Bisher habe ich mich in das Thema der Rule of Five nicht einarbeiten können, wahrscheinlich auch, weil ich für meine Zwecke keinen Bezug finde.

    @Swordfish sagte in Probleme mit dynamischen Arrays (malloc und free):

    tu den t-tor weg. das bringt nix.

    Ich weiß leider nicht, was du mit t-tor meinst, entschuldige. 😞

    Ich freue mich sehr über das nette Miteinander, denn ich fühle mich sehr geholfen, danke!
    Lernen ist ja immer ein Prozess, manchmal flüssig, oft zäh, und die Konversation mit euch beschleunigt meinen Prozess ungemein! 🙂


  • Mod

    @Rav1642 sagte in Probleme mit dynamischen Arrays (malloc und free):

    Bzgl. Rule of Five:
    Mein Cpp-Buch vom Author Jürgen Wolf besagt grob vier Punkte:

    • fertige Container verwenden (in meinem Fall den std::vector<double>)
    • Smart Pointer nutzen (hierzu werde ich mich in Kürze genauer einlesen)
    • durch Smart Pointer sind delete und delete[] unnötig (steigende Konsistenz des Speichers)
    • keine Regel der Rule of Five definieren, sondern das dem Compiler überlassen (das verstehe ich nicht, da ich ja mindestens den Zuweisungsoperator brauche, nicht?)

    Hier hat Herr Wolf ausnahmsweise mal Recht, aber allgemein gilt leider Bücher von Jürgen Wolf sind zum Lernen ungeeignet.



  • @SeppJ sagte in Probleme mit dynamischen Arrays (malloc und free):

    aber allgemein gilt leider Bücher von Jürgen Wolf sind zum Lernen ungeeignet.

    Okay, welches Buch oder welche Bücher sind denn zum Lernen geeignet?



  • @Rav1642 sagte in Probleme mit dynamischen Arrays (malloc und free):

    Ich weiß leider nicht, was du mit t-tor meinst, entschuldige.

    t-tor = d-tor mit Tippfehler. = destructor. Einen leeren hinschreiben ist wie sowas.


  • Mod

    @Rav1642 sagte in Probleme mit dynamischen Arrays (malloc und free):

    @SeppJ sagte in Probleme mit dynamischen Arrays (malloc und free):

    aber allgemein gilt leider Bücher von Jürgen Wolf sind zum Lernen ungeeignet.

    Okay, welches Buch oder welche Bücher sind denn zum Lernen geeignet?

    Diese Liste wird recht gut gepflegt:
    https://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list/388282#388282



  • Ich wollte mich eben um die Referenzen bemühen, aber bin auf Probleme gestoßen.
    Gegeben bspw. meine Operatorenüberladungen:

    // operator overloading
    	Matrix operator- (); //unary
    	friend Matrix operator+ (Matrix m, Matrix n);
    	friend Matrix operator- (Matrix m, Matrix n);
    	friend Matrix operator* (Matrix m, Matrix n);
    	friend Matrix operator* (Matrix m, double d);
    	friend Matrix operator* (double d, Matrix m);
    

    So, wie sie gerade sind, kann ich mit

    Matrix h = Matrix(3, { 1, 1, 0, 2, -40, 5, 20, 6, -3 });
    Matrix g = Matrix(3, { 7, 5, 0, 81, -6, 8, -10, 0, 2 });
    

    problemlos Ausdrücke wie

    ((4 * h) * -(g * h)).print();
    

    nutzen.
    Aber schon wenn ich

    friend Matrix operator* (Matrix& m, Matrix& n);
    

    habe, gibt es Probleme, weil ich in vielen Situationen ja keine Objekte habe, von denen referenziert wird.
    Auch wenn ich im Konstruktor von Matrix den std::vector<double> referenziere, kann ich obige Deklaration mit { ... } nicht mehr nutzen.

    Wie wird das dann gehandhabt?

    @SeppJ sagte in Probleme mit dynamischen Arrays (malloc und free):

    Diese Liste wird recht gut gepflegt:
    https://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list/388282#388282

    Danke, da stöbere ich mal die Tage. 🙂



  • @Rav1642 sagte in Probleme mit dynamischen Arrays (malloc und free):

    weil ich in vielen Situationen ja keine Objekte habe, von denen referenziert wird.

    Bahnhof. Kompilierbares Minimalbeispiel oder das ist nie passiert.



  • @Rav1642 sagte in Probleme mit dynamischen Arrays (malloc und free):

    gibt es Probleme

    Aha. Welche?

    Vermutlich würde const helfen.

    friend Matrix operator* (const Matrix& m, const Matrix& n);
    


  • @Swordfish

    Da ich Matrizen nutze, möchte ich sie in mathematischen Formeln verwenden.
    Das bedeutet, dass

    ((4 * h) * -(g * h))
    

    eine Matrix ergeben soll. Ich müsste sonst für jede Teilrechnung ein Objekt erstellen und das ist schwer suboptimal.



  • @manni66 sagte in Probleme mit dynamischen Arrays (malloc und free):

    Aha. Welche?

    Der Compiler verweigert den Dienst, weil die Operationen nicht definiert seien.

    @manni66 sagte in Probleme mit dynamischen Arrays (malloc und free):

    Vermutlich würde const helfen.

    Gerade getestet, aber bei

    Matrix operator* (const Matrix& m, const Matrix& n) { //... }
    

    lässt der Compiler diesen Aufruf nicht mehr zu:

    if (!(m.getColumns() == n.getRows())) { //...}
    

    Dann kann ich nicht mehr auf Klassenmethoden von m und n zugreifen.



  • @Rav1642 Du zeigen was Du geschrieben und erklären was für Probleme Du haben.



  • @Rav1642 sagte in Probleme mit dynamischen Arrays (malloc und free):

    lässt der Compiler diesen Aufruf nicht mehr zu:
    if (!(m.getColumns() == n.getRows())) { //...}

    @SeppJ sagte in Probleme mit dynamischen Arrays (malloc und free):

    Guck dir auch das Thema 'const-correctness' an. So etwas wie getSize() sollte const sein. Das ist auch etwas, was du jetzt wahrscheinlich nicht unbedingt machen musst, aber du könntest später Probleme bekommen, wenn du es nicht tust. Und wenn du dann Probleme bekommst, musst du gleich sehr viel ändern

    @Rav1642 sagte in Probleme mit dynamischen Arrays (malloc und free):

    Der Compiler verweigert den Dienst,

    Aha

    Matrix.cpp C6666: Dienst verweigert

    Fehlermeldung: Copy&paste


Anmelden zum Antworten