Probleme mit dynamischen Arrays (malloc und free)



  • @manni66 magic O.O



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

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

    @SeppJ Das einzige was mit C-Style nicht geht ist dynamic_cast<> oder?

    Doch, auch das geht.

    Wie denn?

    Der Standard sagt (Kapitel 5.4 in N4296), dass (T) const_cast, static_cast, static_cast gefolgt von const_cast, reinterpret_cast oder reinterpret_cast gefolgt von const_cast macht. Von dynamic_cast steht da nichts. Wie bringst du (T) dazu, sich wie dynamic_cast zu verhalten?



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

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

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

    @SeppJ Das einzige was mit C-Style nicht geht ist dynamic_cast<> oder?

    Doch, auch das geht.

    Wie denn?

    Der Standard sagt (Kapitel 5.4 in N4296), dass (T) const_cast, static_cast, static_cast gefolgt von const_cast, reinterpret_cast oder reinterpret_cast gefolgt von const_cast macht. Von dynamic_cast steht da nichts. Wie bringst du (T) dazu, sich wie dynamic_cast zu verhalten?

    Hm, eigentlich war ich mir sicher, aber wenn es da so steht habe ich mich wohl getäuscht.


  • Mod

    Wäre ja auch komisch, wenn ein C-Feature (wo es dynamic_cast prinzipiell nicht geben kann) sich in C++ anders verhalten würde. Die von @wob zitierte Regel ist ja nur C++Sprachregelung zu dem Verhalten, wie es im C-Standard steht.



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

    Wäre ja auch komisch,

    +1



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

    Zur Speicherverwaltung gehört ja ein bisschen was dazu. Wenn du das manuell machst und das korrekt machen wolltest, noch mehr als das was du bisher gemacht hast. Das hat jetzt aber alles nichts mit der Klasse Matrix zu tun. Eine andere Klasse, die etwas ganz anderes macht, könnte evtl. genau die gleiche Logik zur Speicherverwaltung brauchen.

    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.

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

    Du willst einem Anfänger die korrekte Nutzung von allocator_traits erklären? Das wird spannend.

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

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

    Ein Pool besteht aus im Vorfeld reservierte Ressourcen, damit während der Laufzeit aufwendigens Anfordern von Ressourcen ausbleibt.
    Einen pool allocator stelle ich mir demnach als einen Allocator vor, der ausreichend Speicher bereitstellt und während der Laufzeit stets neu verteilt. Ich hoffe, ich habs getroffen. 😅

    @wob Danke für das Video! 🙂

    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?
    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! 🙂



  • 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. 🙂


Anmelden zum Antworten