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]; } #endifmeine 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
-
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