Matrizenklasse: intelligentes Exceptionhandling gesucht



  • schonwieder könnte ich einen Tipp von Euch brauchen :),
    und zwar geht es diesmal um meine Matrix-klasse. Bisher ist schon einiges drin - gespeichert werden Komplexe Zahlen, die ich selber entworfen habe.

    #ifndef MATRIX_H
    #define MATRIX_H
    
    #include "Complex.h"
    #include "Matrix_exception.h"
    
    //----------------------------------------------------------------------------
    // Matrix
    //----------------------------------------------------------------------------
    
    class Matrix
    {
    public:
    	// constuctors & destructor
        Matrix();
    	Matrix(unsigned int uirows, unsigned int uicolumns);
    	Matrix( const Matrix &m );
    	~Matrix();
    	// member-functions
    	Complex getElement (const unsigned int uirowpos, const unsigned int uicolpos) const;
    	Complex& setElement (const unsigned int uirowpos, const unsigned int uicolpos);
    	unsigned int getRows () const;
    	unsigned int getColumns () const;
    	Matrix& operator= (const Matrix& m);
    	Matrix& operator+= (const Matrix& m);
    	Matrix& operator-= (const Matrix& m);
    
    private:
    	unsigned int _uirow;
    	unsigned int _uicol;
    	Complex **_carray;
    
    };
    //global functions
    std::ostream& operator<< (std::ostream& outstream, const Matrix& m);
    bool operator== (const Matrix& m1, const Matrix& m2);
    bool operator!= (const Matrix& c1, const Matrix& m2);
    const Matrix operator+ (const Matrix& m1, const Matrix& m2);
    const Matrix operator- (const Matrix& m1, const Matrix& m2);
    const Matrix operator* (const Matrix& m1 , const Matrix& m2 );
    
    #endif
    

    Das geht bereits alles. Nun möcht ich aber einen schönen und sicheren Code fabrizieren und wollt mich eh mal in die Exceptions einarbeiten.
    hier mal meine bisherige Exceptionklasse:

    #ifndef MATRIX_EXCEPTION_H
    #define MATRIX_EXCEPTION_H
    
    #include <exception>
    
    class MException : public std::exception
    {  
    public:  
    	MException (const std::string& errorcode): _errStr(errorcode) {} 
        const char* what() const throw() { return _errStr.c_str(); }
    	void showError() { std::cout << this->what(); }
    
    private:  
    	std::string _errStr;
    };  
    
    #endif
    

    und jetzt ein Aufruf in einer Funktion:

    Complex Matrix::getElement (unsigned int uirowpos, unsigned int uicolpos) const
    {
    	if (uirowpos > this->_uirow || uicolpos > this->_uicol || uirowpos == 0 || uicolpos == 0 )
    		throw MException("getElement:position in matrix not available");
    	else 
    		return _carray[uirowpos-1][uicolpos-1];
    }
    

    Irgendwie gefällt mir das nicht so recht - da hat die gute alte C-Syntax mit errno und perror ja mehr Infos geliefert! Entgeht mir da vielleicht eine Funktionalität bei C++? Glaube bei Java war das "werfen" irgendwie besser.
    Und wie catch ich die Standardfehler, z.B. von new und cast?
    Ach ja, kontrolliert wird das in der main-methode mit

    try
    { 
    //...
    }catch (MException& ex)
    	{
    		ex.showError();
    	}
    


  • Gumble schrieb:

    Complex Matrix::getElement (unsigned int uirowpos, unsigned int uicolpos) const
    {
    	if (uirowpos > this->_uirow || uicolpos > this->_uicol || uirowpos == 0 || uicolpos == 0 )
    		throw MException("getElement:position in matrix not available");
    	else 
    		return _carray[uirowpos-1][uicolpos-1];
    }
    

    Irgendwie gefällt mir das nicht so recht - da hat die gute alte C-Syntax mit errno und perror ja mehr Infos geliefert! Entgeht mir da vielleicht eine Funktionalität bei C++? Glaube bei Java war das "werfen" irgendwie besser.

    Was genau willst du denn besser haben? Die Abfrage hat mit der Exceptionbehandlung nichts zu tun, das else ist unnötig und das return geht auch wieder nicht viel schöner. Bleibt eine völlig lesbare Zeile 😉
    Wenn du dir die Überprüfung (und viel andere Arbeit) abnehmen lassen willst, verwende einen std::vector<> und dann .at() (vgl. der andere Matrix-Thread, der hier gerade rumschwirrt 😉 ). Oder assert()e einfach, dass die Positionen gültig sind, falls du damit nur Programm- und keine Eingabefehler abfangen willst.

    Und wie catch ich die Standardfehler, z.B. von new und cast?

    try
    {
    ...
    }
    catch (const std::bad_cast& ex)
    {
        std::cout << ex.what() << std::endl;
    }
    

    bad_cast ist in <typeinfo> (glaube ich, die MSDN will den Header gerade nicht finden) und bad_alloc ist in <new>.
    Catch-en ist per const T& sauberer, showError kann in deiner Klasse ja auch problemslos const sein.

    Hat das eigentlich einen Grund, dass du (AFAIK) schon wieder -= und +=, aber nicht *= als Elementfunktionen geschrieben hast? 🙂



  • Danke op void! Durch so hilfsbereite Member wie Dich macht das programmieren zu später Stunde echt noch Spass 👍 (werde aber dann trotzdem bald die Segel streichen)

    Was genau willst du denn besser haben? Die Abfrage hat mit der Exceptionbehandlung nichts zu tun, das else ist unnötig und das return geht auch wieder nicht viel schöner. Bleibt eine völlig lesbare Zeile 😉
    Wenn du dir die Überprüfung (und viel andere Arbeit) abnehmen lassen willst, verwende einen std::vector<> und dann .at() (vgl. der andere Matrix-Thread, der hier gerade rumschwirrt 😉 ). Oder assert()e einfach, dass die Positionen gültig sind, falls du damit nur Programm- und keine Eingabefehler abfangen willst.

    die böse Else ist gleich rausgeflogen. Danke 🙂 Was ich will? Hm, ein Bier und ein Steak 😉 zur Not tuts auch ne schicke Exceptionhandlingklasse. Bis jetzt wars zum debuggen nicht übel, aber ein fprintf(sterr, "...") und ein exit hätte die selbe Funktion gehabt. Gibts nicht eine globale Variable, in der z.B. die Funktion gespeichert wird, die die Exception geworfen hat? Die könnte man dann im Handler verarbeiten, sprich ausgeben.
    Mit Container/Templates/Vektoren hab ich bisher noch nicht gearbeitet - meinst Du ich soll die "Daten" der Matrix in so ein Ding stopfen? Will doch aber meine eigenen Complex-Klasse dazu verwenden!

    bad_cast ist in <typeinfo> (glaube ich, die MSDN will den Header gerade nicht finden) und bad_alloc ist in <new>.
    Catch-en ist per const T& sauberer, showError kann in deiner Klasse ja auch problemslos const sein.

    ok, dann muss ich halt mehrmals catchen - für jeden Fehler einmal, oder?

    Hat das eigentlich einen Grund, dass du (AFAIK) schon wieder -= und +=, aber nicht *= als Elementfunktionen geschrieben hast? 🙂

    hmm, wieso eigentlich? Vielleicht weil *= fürs Potenzieren recht praktisch ist, aber das fehlt ja eh noch...narf. kommt bald. Soll ich auch noch /= machen? Das braucht man doch so gut wie nie?! will mich jetzt ans Übel ranwagen: determinante und inverse Matrix. urg. 🙄



  • Hui, danke 🙂

    Gumble schrieb:

    Gibts nicht eine globale Variable, in der z.B. die Funktion gespeichert wird, die die Exception geworfen hat? Die könnte man dann im Handler verarbeiten, sprich ausgeben.

    Du könntest dir ein Exception-Werfen-Makro schreiben, dass an den übergebenen String noch gleich die Zeile (__LINE__) und die Funktion (__FUNCTION__, ist aber nicht standardisiert) anhängt. Wenn du aber nur einen Weg brauchst, eigene Logikfehler zu finden und unfreundlich darauf hingewiesen zu werden, ist das Standard-assert() aus <cassert> vielleicht geeigneter als der Ausnahmemechanismus.

    Mit Container/Templates/Vektoren hab ich bisher noch nicht gearbeitet - meinst Du ich soll die "Daten" der Matrix in so ein Ding stopfen? Will doch aber meine eigenen Complex-Klasse dazu verwenden!
    

    Dafür ist std::vector ja ein Template 🙂 std::vector<Complex> wäre hier z.B. naheliegend als Containertyp für die Matrix.

    ok, dann muss ich halt mehrmals catchen - für jeden Fehler einmal, oder?

    Was willst du denn beim Catchen machen? Viele catch-Blöcke braucht man eigentlich selten. Wenn es nur ums Ausgeben geht, reicht doch:

    catch (const std::exception& e)
    {
        std::cout << e.what() << std::endl;
    }
    

    (verwende ich so in etwa jedenfalls)
    Das fängt dann alle von std::exception abgeleiteten Klassen, was praktischer Weise alle Standardausnahmen sind. Den Klassennamen der Exception kann man leider nicht portabel ausgeben.

    So, und jetzt ist auch hier Schicht...


Anmelden zum Antworten