Programmabsturz (vermutlich Zeigerfehler) bei zugriff auf matrix unter Benutzung der TNT library (Array2D)



  • Hi...
    ich bastel hier grad an nem interface zwischen meinem eigentlichen Programm und der TNT library (http://math.nist.gov/tnt/download.html).
    Falls die Frage aufkommt, warum?
    Ich soll das so machen. Falls mein chef sich irgendwann entscheidet, eine andere library zu benutzen oder sie selber zu schreiben, muss so nicht das ganze Programm umgeschrieben werden, sondern nur das interface 😉

    jetzt zu dem Problem:
    das programm stürzt während der laufzeit ab, wenn ich auf eine matrix zugreife, aber nur wenn ich nicht auf die erste zeile zugreife.
    ich vermute daher einen zeiger- und logikfehler meinerseits, da die library bei anderen programmen funktioniert.

    ein funktionierender zugriff in der main könnte zB. so aussehen:

    #include <iostream>
    #include "interface-test.h"
    
    int main()
    {	
    	int x1=5;
    	int y1=5;
    	Matrix <int> test1(x1,y1);
    	std::cout << "Matrix1: \n" << test1(0,1) << std::endl;
    }
    

    wobei aber sowas abstürzen würde:

    ...
    std::cout << "Matrix1: \n" << test1(1,0) << std::endl;
    ...
    

    hier ist die interface datei:

    #ifndef MATRIX_INTERFACE_H_
    #define MATRIX_INTERFACE_H_
    #define maxdim 10000		 /* Max dimension for the matrix/vector
    								If the dimension of a new matrix is higher,
    								it will be cutted to this dimension 
    							 */
    
    #include "tnt.h"
    
    template <class temp>
    class Matrix
    {
    private:
    	unsigned int itsRows;
    	unsigned int itsColumns;
    	TNT::Array2D<temp> *itsArray2D;
    
    public:
    	Matrix(unsigned int rows, unsigned int columns);
    	~Matrix();
    
    	//operator
    	inline temp& operator()(unsigned int i, unsigned int j);
    
    };
    
    // C O N S T R U C T O R  for matrixes
    template<class temp>
    Matrix<temp>::Matrix(unsigned int rows, unsigned int columns):
    itsRows(rows), itsColumns(columns)
    {
    	if (rows > maxdim) rows = maxdim;
    	if (columns > maxdim) columns = maxdim;
    
    	itsArray2D = new TNT::Array2D<temp>(rows, columns);
    }
    
    // D E S T R U C T O R  for matrixes
    template<class temp>
    Matrix<temp>::~Matrix()
    {
        delete itsArray2D;
        itsArray2D = 0;
    }
    
    //O P E R A T O R  overloading
    template<class temp>
    inline temp& Matrix<temp>::operator()(unsigned int i, unsigned int j)
    {
    	return *itsArray2D[i][j];
    }
    
    #endif
    

    meine interface klasse "Matrix" greift auf die "Array2D" Klasse der TNT library zu, wobei da die Operatorüberladung auf der Zeile 140 genutzt wird (tnt_array2d.h):

    template <class T>
    inline T* Array2D<T>::operator[](int i) 
    { 
    #ifdef TNT_BOUNDS_CHECK
    	assert(i >= 0);
    	assert(i < m_);
    #endif
    
    return v_[i]; 
    
    }
    

    wobei gilt (array2d.h zeile 46):

    Array1D<T*> v_;
    

    diese greift wiederrum auf die "Array1D" Klasse der TNT library zu (tnt_array1d.h):

    template <class T>
    inline T& Array1D<T>::operator[](int i) 
    { 
    #ifdef TNT_BOUNDS_CHECK
    	assert(i>= 0);
    	assert(i < n_);
    #endif
    	return data_[i]; 
    }
    

    wobei gilt (array1d.h zeile 47):

    T* data_;				/* this normally points to v_.begin(), but
                                 * could also point to a portion (subvector)
    							 * of v_.
                                */
    

    ich hab schon ne menge geändert und vereinfacht, trotzdem stürzt das prog während der laufzeit ab...
    ich weiß, ich hab hier nen ganzen batzen hingeschrieben, doch bitte helft mir...
    ist echt nervig, wenn man tagelang an so nem fehler sitzt und seinen fehler nicht erkennt 😉

    ich hab den fehler per debugging bis zum return sprung (tnt_array2d.h zeile 148, hier in dem Array2D-ausschnitt zeile 9) zurückverfolgt. und zwar wenn er zurück in die "Matrix" klasse springt (d.h. es ist alles aus der Array2D und Array1D klasse ausgewertet und er will den wert der Matrix klasse übergeben), genau zu dem zeitpunkt stürzt er ab... was ich aber nicht nachvollziehen kann

    weiß da jemand rat?
    würd nur ungern an nem gehirnknoten sterben 😉

    herzlichen Dank schonmal
    Kleriker



  • ich tippe auf das hier.

    //O P E R A T O R  overloading
    template<typename temp>
    inline temp& Matrix<temp>::operator()(unsigned int i, unsigned int j)
    {
        //return *itsArray2D[i][j];
        return itsArray2D[i][j];
    }
    

    nehmen wir mal an du hast für den typ temp, int eingesetzt

    kommt sowas raus

    inline int& Matrix::operator()(unsigned int i, unsigned int j)
    {
        return *itsArray2D[i][j];
    }
    

    wir nehmen jetzt an das itsArray2D[i][j] einen integer zurück gibt.
    dann liefert *itsArray[i][j] blödsinn.
    du dereferenzierst einen integer der irgend einen wert hat, das kann dann auf irgendeinen speicherbereich zeigen, und du kriegst einen segfault.



  • wir nehmen jetzt an das itsArray2D[i][j] einen integer zurück gibt.

    itsArray2D[i][j] liefert doch keinen integer zurück sondern einen zeiger

    template <class T>
    inline T* Array2D<T>::operator[](int i)
    {
    #ifdef TNT_BOUNDS_CHECK
        assert(i >= 0);
        assert(i < m_);
    #endif
    
    return v_[i];
    
    }
    

    wenn also ein zeiger zurück gegeben wird, dann macht itsArray2D[i][j] sinn.
    abgesehen davon, würde die variante ohne * nicht funktionieren... die fehlermeldung würde dann ungefähr lauten, dass er int nicht auf int
    hinbekommt



  • ja, es liefert einen zeiger auf ein proxy objekt, dieses proxy objekt selber hat einen überladenen opearor[] implementiert.

    das ist ein trick um mehrdimensionales adressieren per operator[] zu ermöglichen,
    da es in c++ keinen operator[][] oder operator[][]...[] gibt.

    template <class T>
    inline T* Array2D<T>::operator[](int i)
    {
    #ifdef TNT_BOUNDS_CHECK
        assert(i >= 0);
        assert(i < m_);
    #endif
    
    return v_[i];
    
    } 
    
    //das genau passiert
    ProxyObjekt* pProxy = itsArray2D[j];
    int deinWert = pProxy[i];
    
    //oder in einer zeile
    int deinWert = itsArray2D[j][i];
    


  • nachtrag.

    und falls array2D wirklich nicht so implementiert ist um mehrdimensionalität per proxy objekt zu machen, und einfach itsArray2D[j][i] nicht ausreicht um an den zellenwert zu kommen, dann müsste es so gehen (*itsArray2D[j])[i];

    aber, da es eben möglich ist, und library entwickler sichs drauf stehen eine klare ausdrucksweise in ihren libraries zu haben, denke ich das die erste methode die richtige ist (ohne in den code geschaut zu haben)



  • ja, es liefert einen zeiger auf ein proxy objekt, dieses proxy objekt selber hat einen überladenen opearor[] implementiert.

    das ist ein trick um mehrdimensionales adressieren per operator[] zu ermöglichen,
    da es in c++ keinen operator[][] oder operator[][]...[] gibt.

    ja ich denke du hast vollkommen recht

    wenn ich aber itsArray2D[i][j] verwende, bekomme ich den fehler:

    error C2440: 'return': 'int *' kann nicht in 'int &' konvertiert werden

    und wenn ich (*itsArray[i])[j] bekomm ich die fehler:

    error C2593: 'Operator *' ist mehrdeutig



  • Nachtrag:

    ich muss

    inline temp& Matrix<temp>::operator()(unsigned int i, unsigned int j);
    

    mit temp& als rückgabewert definieren, weil ich auch darauf zugreifen möchte um einen wert einzutragen
    trotzdem hatte ich es mal mit temp statt temp& als rückgabe probiert habe, und das hatte aber ebenfalls nicht funktioniert.



  • Kleriker schrieb:

    und wenn ich (*itsArray[i])[j] bekomm ich die fehler:

    error C2593: 'Operator *' ist mehrdeutig

    (*(itsArray[i]))[j];

    wenn das nicht klappt, les ich mal TNT sourcen 🙂



  • inpimp schrieb:

    (*(itsArray[i]))[j];

    bekomm immer noch die fehlermeldung

    error C2593: 'Operator *' ist mehrdeutig


  • Administrator

    Ehm, wenn ich mich mal dazwischen schalten darf ...
    Das Problem ist äusserst einfach ...

    Deklaration:

    TNT::Array2D<temp> *itsArray2D;
    

    Korrekte Verwendung:

    return (*itsArray2D)[i][j];
    

    Wenn du sowas machst:

    return itsArray2D[i][j];
    

    Dann geht es zum i-ten Array2D und dann wendet es darauf den operator [] an, was einem ein int* zurückgibt. Kompilerfehler garantiert.
    Ein Proxy wird übrigens nicht verwendet, das kannst du in der Dokumentation nachlesen.

    Wenn du das da machst:

    return *itsArray2D[i][j];
    

    Dann wird noch das int* dereferenziert und somit gibt es keinen Kompilerfehler, dafür wahrscheinlich ein Segfault. Du greifst ja auf das i-te Array2D zu, welches nicht existiert.

    Beste Lösung:

    template <class temp>
    class Matrix
    {
    private:
        unsigned int itsRows; // Wofür eigentlich? TNT::Array2D bietet sowas schon an.
        unsigned int itsColumns; // Wofür eigentlich? TNT::Array2D bietet sowas schon an.
        TNT::Array2D<temp> itsArray2D; // ZEIGER WEG
    
    public:
        Matrix(unsigned int rows, unsigned int columns);
        ~Matrix();
    
        //operator
        inline temp& operator()(unsigned int i, unsigned int j);
    };
    
    // C O N S T R U C T O R  for matrixes
    template<class temp>
    Matrix<temp>::Matrix(unsigned int rows, unsigned int columns)
      : itsRows(rows),
      , itsColumns(columns)
      , itsArray2D(rows > maxdim ? maxdim : rows, columns > maxdim ? maxdim : columns)
    {
      // Das Objekt direkt initialisieren.
    }
    
    // D E S T R U C T O R  for matrixes
    template<class temp>
    Matrix<temp>::~Matrix()
    {
        /*
        Muss man nicht mehr löschen.
        delete itsArray2D;
        itsArray2D = 0;
        */
    }
    
    //O P E R A T O R  overloading
    template<class temp>
    inline temp& Matrix<temp>::operator ()(unsigned int i, unsigned int j)
    {
        // Dereferenzierung weg!
        return itsArray2D[i][j];
    }
    

    Grüssli



  • wow, scheint alles zu klappen...
    recht herzlichen dank 🙂


Anmelden zum Antworten