Matrizendarstellung in C++





  • Es fehlt noch mindestens:
    Was ist std::complex?



  • Meine Frage ist nur wie ich das Template dafür gestalte, komme da einfach nicht weiter.

    Aber dass die Leute hier einen so attackieren hätte ich nicht gedacht.

    Bin kein Programmierer, bin noch am lernen.

    LG



  • @KelbsSohn Wer hat Dich attackiert? Hier sehe ich keine Attacke. Wenn Deine Klassenkameraden Dich attackieren, können wir doch nix dafür.



  • @mgaeckler Naja, ich publiziere mein Code den ich geschrieben habe und bekomme als Antwort Aha, Facepalm. Anstatt direkt zu sagen, "hey, du hast deine Frage vergessen" oder sowas in der Art. Aber egal, ich möchte nur einen Ansatz und keine geschriebene Lösung.

    LG



  • Naja, der Facepalm war ein Hinweis auf einen offensichtlichen Fehler in deiner Klasse. Im Konstruktor wird Speicher reserviert, im Destruktor nicht wieder freigegeben.

    Da du keine Frage gestellt hattest, hast du eben Antworten bekommen zu Dingen, die falsch in deinem Code sind oder verbesserungswürdig sind. @Swordfish hat in seiner Antwort ein paar Fragen gestellt. Die Idee hinter den Fragen ist natürlich, dass du dich damit befasst. Hättest du z.B. std::vector verwendet, wäre das Speicherleck nicht passiert. Für deine getemplatete Klasse kannst du dann std::array verwenden. Und generell lies zu diesem Thema über die rule of zero (rule of three / rule of five). Und so weiter.

    Womit hast du denn beim Template Probleme? Was genau meinst du mit "wie ich das Template gestalte"? Also am besten intern mit einem std::array arbeiten, würde ich sagen, denn die Dimensionen stehen ja fest.

    Merke: es ist schlecht, Code hier einzustellen und dann mit vielen Konjunktiven zu beschreiben. Dann weiß niemand, was du genau wissen willst und du bekommst dann eben irgendwelche Antworten zu Themen, die mit deinem Code zu tun haben und dem Antwortschreiber eben gerade in den Kopf kommen.



  • @wob Ja, ich hatte da die Freigabe des Speichers, hab ich aber weggenommen, weil ich nicht sicher bin, ob ich mit dem Pointer-Array weiterarbeite bzw. ob das überhaupt möglich ist.

    Ich möchte auch keine std::vector, std::array usw. benutzen. Es geht mir nur darum, ich habe eine Complex-Klasse und eine Rational-Klasse. Dafür möchte ich ein Template Matrizen schreiben, der mir die Ausgabe beider Klassen als Matrizen darstellt.

    Und danke, werde dies berücksichtigen bevor ich ein Topic eröffne. 🙂



  • Meine Frage ist nur wie ich das Template dafür gestalte, komme da einfach nicht weiter.
    ich möchte ein Template zur Matrizendarstellung implementieren.

    OK. Noch nicht fertig, aber den template<class T, unsigned uiRows, unsigned uiColumns> Teil hast du schonmal. Das ist so OK.

    Der Zahlentyp und die Anzahl der Zeilen und Spalten sollen als Templateparameter angegeben werden.

    Hast du schon, passt auch.

    Die Klasse soll auch ein Ausgabeoperator, sowie Addition- und Subtraktionsoperatoren als friend Operatoren.

    Signatur für den Ausgabeoperator hast du auch schon, sieht auch OK aus. Die Implementierung ist halt falsch weil du nur eine Schleife für die Spalten hast - du brauchst aber eine Schleife für die Spalten und darin nochmal eine für die Zeilen. Oder umgekehrt, auf jeden Fall zwei verschachtelte Schleifen. (OK, es geht auch mit einer Schleife, aber es ist vermutlich einfacher mit zwei.)

    Für Addition und Subtraktion hast du die falschen Operatoren versucht (++ und --).

        friend Matrix operator+(const Matrix& a, const Matrix& b){
            Matrix result;
            // compute result
            return result;
        }
    
        friend Matrix operator-(const Matrix& a, const Matrix& b) {
            Matrix result;
            // compute result
            return result;
        }
    

    Instanziieren will ich den Datentypen mit unsigned int und anwenden will ich das auf meine Klassen Rational und Complex.

    Für mich nicht verständlich was du damit meinst. Was ist hier der Unterschied zwischen instanziieren und anwenden?

    Ein paar allgemeine Tips noch:

    • Vergiss dynamische Speicheranforderung mit new. Die Grösse der Matrix ist ja über Templateparameter gegeben, d.h. du kannst z.B. einfach std::array verwenden.
    • Bau dir als erstes mal eine Funktion zum Zugriff auf ein Element über row-number und column-number
    • Fang erstmal damit an nur das Matrix-Template zu implementieren und vergiss die Rational und Complex Klassen. Fang mit Matrix<double, ...> an. Wenn das dann soweit passt, dann kannst du mit Rational, Complex etc. weitermachen.

    Beispiel wie das mit std::array aussehen könnte:

    template <class T, unsigned uiRows, unsigned uiColumns>
    class Matrix {
    public:
        Matrix() : m_elements{} {}
        // compilergenerierter Destruktor ist OK
        // compilergenerierter Assignment-Operator ist OK
        // compilergenerierter Move-Operator ist OK
    
        friend ostream& operator<<(ostream& os, const Matrix& crArg) {
            for (unsigned row = 0; row < uiRows; row++) {
                for (unsigned column = 0; column < uiColumns; column++) {
                    T const& e = get(row, column);
                    // ...
                }
            }
        }
    
        friend Matrix operator+(const Matrix& a, const Matrix& b) { ... }
        friend Matrix operator-(const Matrix& a, const Matrix& b) { ... }
    
        T& get(unsigned row, unsigned column) {
            return m_elements[row * uiColumns + column];
        }
    
        T const& get(unsigned row, unsigned column) const {
            return m_elements[row * uiColumns + column];
        }
    
    private:
        std::array<T, uiRows * uiColumns> m_elements;
    };
    


  • @KelbsSohn sagte in Matrizendarstellung in C++:

    Ich möchte auch keine std::vector, std::array usw. benutzen.

    Dann nimm ein normales Member-Array statt dessen. Kein dynamisch erzeugtes.



  • Dieser Beitrag wurde gelöscht!


  • @Swordfish sagte in Matrizendarstellung in C++:

    int, unsigned, doch was anderes? Entscheide Dich.

    Stimmt. Fixed.

    ps: Beim Editieren hat mich grad eiskalt eine mir bisher noch nicht bekannte Funktion des Forums erwischt: wenn man per Copy+Paste etwas einfügt was mit > anfängt, dann wird automatisch > vor allen folgenden Zeilen des kopierten Texts eingefügt. Da ich's erst bemerkt habe nachdem ich schon auf "Absenden" gedrückt hab durfte ich das dann alles wieder per Hand wegmachen. 😞



  • @KelbsSohn sagte in Matrizendarstellung in C++:

    Ich möchte auch keine std::vector, std::array usw. benutzen.

    Dann läuft das auf eine Allocator Klasse hinaus, wenn man es denn „richtig“ machen will.



  • @john-0 sagte in Matrizendarstellung in C++:

    @KelbsSohn sagte in Matrizendarstellung in C++:

    Ich möchte auch keine std::vector, std::array usw. benutzen.

    Dann läuft das auf eine Allocator Klasse hinaus, wenn man es denn „richtig“ machen will.

    Warum? Hier wird doch überhaupt kein dynamischer Speicher benötigt, da die Dimensionen Template-Parameter sind und somit mit T data[rows * cols] ein Array angelegt werden kann. Wo muss da ein Allocator ins Spiel kommen?



  • Vielleicht möchte man sich bei der Matrixgröße nicht durch den Stack einschränken lassen.



  • @wob sagte in Matrizendarstellung in C++:

    Warum? Hier wird doch überhaupt kein dynamischer Speicher benötigt, da die Dimensionen Template-Parameter sind und somit mit T data[rows * cols] ein Array angelegt werden kann. Wo muss da ein Allocator ins Spiel kommen?

    std::array & Co. eliminiert die Möglichkeit die Move-Semantik bei nicht trivialen Matrizendimensionen zu nutzen, dazu hat move auf allen Standardcontainer mit dem Standard Allocator O(1) Laufzeitverhalten. Das geht mit std::array nicht, da hat man ohne wirklichen Grund O(M×N).

    Sicherlich lassen sich mit viel Template Metaprogramming auch zwei Matrizen korrekt multiplizieren, wenn man hier nicht nur Hadamard-Produkt implementieren will. Für Anfänger dürfte das mit dynamsicher Allokation während der Laufzeit und simplen Größenvergleichen leichter umzusetzen sein.



  • Dann könnte man immer noch das gesamte Matrix-Objekt auf dem Freispeicher (Heap) erstellen, aber dafür sollte die Matrixklasse frei von Speicherallokationen sein.



  • Oder man implementiert eine Small Matrix Optimization nach Vorbild der Small String Optimization.



  • Man kann auch gerne unique_ptr<T[]> verwenden.

    Wenn man unbedingt möcht kann man sich auch sowas wie unique_ptr<T[]> selbst basteln und das dann verwenden.

    Bloss bitte bitte nicht Resourcenverwaltung mit anderen Dingen zusammen in eine Klasse packen. Das geht viel viel öfter schief als es gut geht.


Anmelden zum Antworten