gelöst: Problem bei doppelter Zeigerarithmetik
-
Kiigass schrieb:
danke für die Antwort. Ich bin noch nicht dazu gekommen die Lösung von dir auszuprobieren, aber leider wäre sie laut Aufgabenstellung auch nicht zulässig.
Was wäre nicht zulässig? vernünftige Container verwenden? Oder die zusätzliche Deferenzierung?
Um letztere wirst du nicht herumkommen, wenn du den jetzigen Aufbau beibehalten willst/mußt:
m.mat ist ein Zeile** - ein Zeiger auf ein Zeile*-Array
m.mat[i] ist ein Element dieses Arrays, also ein Zeiger auf ein Zeile
*m.mat[i] ist das Objekt hinter diesem Zeiger
(*m.mat[i])[j] ruft die op[]-Methode der Zeile auf
-
CStoll schrieb:
Kiigass schrieb:
danke für die Antwort. Ich bin noch nicht dazu gekommen die Lösung von dir auszuprobieren, aber leider wäre sie laut Aufgabenstellung auch nicht zulässig.
Was wäre nicht zulässig? vernünftige Container verwenden? Oder die zusätzliche Deferenzierung?
Um letztere wirst du nicht herumkommen, wenn du den jetzigen Aufbau beibehalten willst/mußt:
m.mat ist ein Zeile** - ein Zeiger auf ein Zeile*-Array
m.mat[i] ist ein Element dieses Arrays, also ein Zeiger auf ein Zeile
*m.mat[i] ist das Objekt hinter diesem Zeiger
(*m.mat[i])[j] ruft die op[]-Methode der Zeile aufJa die zusätzlich Dereferenzierung bzw. genauer: Die Syntaxänderung zum Aufruf der Daten ist unzulässig. Laut Aufgabenstellung muss die Syntax sein: "m[i][j]".
Allerdings gibt es dafür ja auch den überladenen operator[] der eigentlich das Objekt zurück geben sollte (also bei der Klasse Matrix soll er ein Objekt vom Typ Zeile zurück geben und bei der Klasse Zeile einen Integer). Vllt steckt auch da das Problem.
-
Kiigass schrieb:
Ja die zusätzlich Dereferenzierung bzw. genauer: Die Syntaxänderung zum Aufruf der Daten ist unzulässig. Laut Aufgabenstellung muss die Syntax sein: "m[i][j]".
Allerdings gibt es dafür ja auch den überladenen operator[] der eigentlich das Objekt zurück geben sollte (also bei der Klasse Matrix soll er ein Objekt vom Typ Zeile zurück geben und bei der Klasse Zeile einen Integer). Vllt steckt auch da das Problem.Warum verwendest du den dann nicht in deinen Funktionen? Das Teil sollte nicht die Aufrufe von außen ersetzen, sondern deine missglückten Aufrufe ma.mat[i][j] in den Operatoren.
-
Nexus schrieb:
SeppJ schrieb:
Ich würde ein Proxyobjekt zurückgeben, welches erst einmal nur die Zugriffe umlenkt. Und erst wenn man mit diesem Objekt eine neue Matrix erstellt, wird kopiert.
Copy-On-Write ist problematisch, solange man
operator[]mit Schreib- und Lesezugriff hat. Dann werden nämlich auch Nicht-Änderungen als Änderungen angesehen. Eine Möglichkeit wäre separate Getter und Setter, was dann die Syntax aber weniger schön macht.Ich hatte an so etwas gedacht (entschuldigt den schnellen Hack, ich wollte gerade keine ganze Matrixklasse schreiben, sondern nur zeigen, wie ich transponieren würde):
#include <iostream> #include <vector> #include <cassert> template <class T> class Matrix; template <class T> class TransposedMatrix { private: const Matrix<T> & matrix; TransposedMatrix(Matrix<T> const &matrix); public: const T& operator()(size_t x, size_t y) const; friend class Matrix<T>; }; template <class T> class Matrix { private: typedef typename std::vector<T>::size_type size_t; std::vector<T> data; size_t nrows, ncols; public: Matrix( size_t nrows , size_t ncols): data(nrows*ncols), nrows(nrows), ncols(ncols) {} Matrix( TransposedMatrix<T> const & other): nrows(other.matrix.ncols), ncols(other.matrix.nrows) { data.reserve(ncols*nrows); for (size_t i = 0; i < nrows; ++i) for(size_t j = 0; j < ncols; ++j) data.push_back(other(i,j)); } T& operator()(size_t x, size_t y) { assert(x < nrows and y < ncols); return data[x*ncols + y]; } const T& operator()(size_t x, size_t y) const { assert(x < nrows and y < ncols); return data[x*ncols + y]; } const TransposedMatrix<T> transpose() const { return *this; } friend class TransposedMatrix<T>; }; template <class T> TransposedMatrix<T>::TransposedMatrix(Matrix<T> const &matrix): matrix(matrix) {} template <class T> const T& TransposedMatrix<T>::operator()(size_t x, size_t y) const { assert(y < matrix.nrows and x < matrix.ncols); return matrix.data[y*matrix.ncols + x]; } using namespace std; int main() { Matrix<int> foo(5,3); for(int i = 0; i < 5; ++i) for (int j = 0; j < 3; ++ j) foo(i,j) = i*10 + j; for(int i = 0; i < 5; ++i) { for (int j = 0; j < 3; ++ j) cout << foo(i,j) << "\t"; cout << endl; } cout << endl; for(int i = 0; i < 3; ++i) { for (int j = 0; j < 5; ++ j) cout << foo.transpose()(i,j) << "\t"; cout << endl; } cout << endl; Matrix<int> transposed = foo.transpose(); for(int i = 0; i < 3; ++i) { for (int j = 0; j < 5; ++ j) cout << transposed(i,j) << "\t"; cout << endl; } }P.S.: So im Nachhinein gesehen ist das unnötig kompliziert, einfache Überladung von transpose hätte es auch getan. Naja, hat immerhin Spaß gemacht das zu programmieren.

-
CStoll schrieb:
Kiigass schrieb:
Ja die zusätzlich Dereferenzierung bzw. genauer: Die Syntaxänderung zum Aufruf der Daten ist unzulässig. Laut Aufgabenstellung muss die Syntax sein: "m[i][j]".
Allerdings gibt es dafür ja auch den überladenen operator[] der eigentlich das Objekt zurück geben sollte (also bei der Klasse Matrix soll er ein Objekt vom Typ Zeile zurück geben und bei der Klasse Zeile einen Integer). Vllt steckt auch da das Problem.Warum verwendest du den dann nicht in deinen Funktionen? Das Teil sollte nicht die Aufrufe von außen ersetzen, sondern deine missglückten Aufrufe ma.mat[i][j] in den Operatoren.
hmm entweder verstehst du mich nicht oder ich dich nicht, reden wir an einander vorbei?
Das Problem tritt ja beim Überladen von operator+ bzw operator* auf. Ich hatte oben aber auf den operator[] angespielt. Also sicherlich könnte ich in meiner Funktion das so schreiben wie du es mir vorgescchlagen hast, aber dann würde das Problem außerhalb doch immer noch bestehen. Oder bin ich grad zu blöd?
-
Nochmal langsam von vorne: Dein operator[] ist in Ordnung und macht das, was er soll - das heißt, es ist kein Problem für die Anwender der Klasse, per
m[i][j]auf die Matrix-Elemente zuzugreifen. Aber in den arithmetischen Operatoren verwendest du nicht diesen Operator, sondern greifst direkt auf deine internen Daten zu - dort mußt du die Zeiger dann oft genug dereferenzieren, um an die richtige Stelle zu kommen.
-
CStoll schrieb:
Nochmal langsam von vorne: Dein operator[] ist in Ordnung und macht das, was er soll - das heißt, es ist kein Problem für die Anwender der Klasse, per
m[i][j]auf die Matrix-Elemente zuzugreifen. Aber in den arithmetischen Operatoren verwendest du nicht diesen Operator, sondern greifst direkt auf deine internen Daten zu - dort mußt du die Zeiger dann oft genug dereferenzieren, um an die richtige Stelle zu kommen.okay ich glaube ich habe das verstanden, aber dann stellt sich mir die Frage warum er in den "arithmetischen Operatoren" nicht den überladenen operator[] benutzt. Ist das immer so? und wenn ja warum?
ps: danke für deine Geduld!

pps: in der print()-Funktion kommt es auch zu einem Fehler, aber wenn der Zugriff wie du sagst, über
m[i][j]möglich ist, müsste dann dort nicht einfach ein Integer stehen? Also warum kommt es zu einem Fehler?
-
Kiigass schrieb:
CStoll schrieb:
Nochmal langsam von vorne: Dein operator[] ist in Ordnung und macht das, was er soll - das heißt, es ist kein Problem für die Anwender der Klasse, per
m[i][j]auf die Matrix-Elemente zuzugreifen. Aber in den arithmetischen Operatoren verwendest du nicht diesen Operator, sondern greifst direkt auf deine internen Daten zu - dort mußt du die Zeiger dann oft genug dereferenzieren, um an die richtige Stelle zu kommen.okay ich glaube ich habe das verstanden, aber dann stellt sich mir die Frage warum er in den "arithmetischen Operatoren" nicht den überladenen operator[] benutzt. Ist das immer so? und wenn ja warum?
Dein Index-Operator wird nur angewendet, wenn der linke Operand eine Matrix ist - wie in
m[i][i]. Bei deinen Aufrufenm.mat[i][j]steht dort aber ein Zeiger - und der hat seinen eigenen (eingebauten) Index-Operator.pps: in der print()-Funktion kommt es auch zu einem Fehler, aber wenn der Zugriff wie du sagst, über
m[i][j]möglich ist, müsste dann dort nicht einfach ein Integer stehen? Also warum kommt es zu einem Fehler?In der print-Funktion kannst du *this als Matrix-Objekt verwenden, mit dem du den Index-Operator nutzen kanns, das sieht dann so aus
cout<<(*this)[i][/j]<<endl;
-
vielen dank für die kleine Nachhilfestunde, ich sah den Wald vor lauter Bäumen schon nicht mehr. Damit sind meine Probleme gelöst! Dank dir!

-
SeppJ schrieb:
Kiigass schrieb:
und wenn wir grad dabei sind: Kann mir jemand sagen ob es richtig von mir war, die Zeile 38 in matrix.cpp aus zu kommentieren? Wenn ich sie drin lasse meldet der Compiler: "doppeltes free"
Ja, das ist richtig, das auszukommentieren. Dein delete auf das mat ruft den Zeilendestruktor auf, welcher dann wieder ein delete für die einzelnen Werte aufruft.
Und das doppelte free sagt dir nicht dein Compiler, sondern deine Laufzeitumgebung. Das ist ein ganz großer Unterschied.
Nicht wirklich. mat ist vom Typ Zeile** und nicht Zeile*. Da wird kein Destruktor aufgerufen. Das auskommentieren ist also falsch und führt zum Speicherleck.