Problem mit get-Methode



  • An die Sache mit den Vektoren hab ich auch schon gedacht. Ich soll aber eigene Felder benutzen!

    Von daher kann ich leider mit deinem Tip nicht viel anfangen. Wäre daher nett, wenn du mir sagen könntest, wo der Hase im Pfeffer liegt!



  • int operator[]( std::array<int, 2> const& indices ) const;  // const-correctness beachten!
        int& operator[]( std::array<int, 2> const& indices )       // Sicherlich auch ganz nützlich, wenn man schreibend zugreifen kann
    

    FTFY 😃
    (Mit init-list benutzen, ginge aber natürlich auch mit dem Funktionsoperator)


  • Mod

    Habt ihr denn nicht gelernt wie das geht, wenn ihr das selber machen sollt? Die Regel der großen Drei wurde schon genannt. Wahrscheinlich ist noch viel mehr falsch, weil man vieles falsch machen kann und du nicht alles gezeigt hast. Aber wir können dir hier nicht alles beibringen, worauf es ankommt. Im Prinzip ist deine erste Aufgabe, std::vector nachzuprogrammieren. Dazu brauchst du mindestens schon einmal folgende Stichworte:
    http://en.wikipedia.org/wiki/Rule_of_three_(C%2B%2B_programming)
    http://en.wikipedia.org/wiki/RAII

    Wenn das fertig und getestet(!) ist, dann bastelst du damit deine Matrixklasse. Und zwar wirklich nur 1D! Das 2D zu machen ist (fast immer*) Unsinn.

    *: Diese Relativierung bezieht sich nicht auf die hier vorliegende Aufgabe. Naturwissenschaftler mögen keine absoluten Aussagen, wenn sie nicht in jedem Fall stimmen. Die Relativierung ist für die Klugscheißer im Forum gedacht, die ansonsten einen Flamewar starten würden, dass sie einen Sonderfall kennen, in dem das sinnvoll ist. Daher nochmal absolute Aussage: Solch ein Fall liegt hier nicht vor. 1D ist angesagt.

    Sone schrieb:

    int operator[]( std::array<int, 2> const& indices ) const;  // const-correctness beachten!
        int& operator[]( std::array<int, 2> const& indices )       // Sicherlich auch ganz nützlich, wenn man schreibend zugreifen kann
    

    FTFY 😃
    (Mit init-list benutzen, ginge aber natürlich auch mit dem Funktionsoperator)

    Wo soll denn da der Vorteil sein, außer, dass es umständlicher+ ist?

    +: Ich bin nicht mehr sicher, ob das in C++ als Vorteil oder als Nachteil gilt 🙂



  • SeppJ schrieb:

    Sone schrieb:

    int operator[]( std::array<int, 2> const& indices ) const;  // const-correctness beachten!
        int& operator[]( std::array<int, 2> const& indices )       // Sicherlich auch ganz nützlich, wenn man schreibend zugreifen kann
    

    FTFY 😃
    (Mit init-list benutzen, ginge aber natürlich auch mit dem Funktionsoperator)

    Wo soll denn da der Vorteil sein, außer dass es umständlicher ist?

    🕶 🕶 🕶 🕶 🕶 🕶 🕶 🕶 🕶

    Naja, und außerdem passt es besser. Wenn du eine Matrix auslesen willst, dann nimmst du halt den operator[] .

    Siehe auch Boost, AFAIR mit boost::range machen die das da....



  • Übrigens: Wie intuitiv ist schon

    a.get(1, 2) = 8;
    

    Viel lieber:

    a[{1, 2}] = 8;
    


  • So Leute, ich probier's nochmal. Ich würde sehr gerne an meinem Code weiterarbeiten. Vielleicht könnt ihr mich ja auf so manchen Fehler hinweisen? Ich kopier jetzt mal allen Code rein:

    #include<iostream>
    #include"U1A3und4header.h"
    using namespace std;
    
    int main()
    {
    	matrix matrixLinks(4,4);
    	matrix matrixRechts(4,4);
    
    return 0;
    }
    
    #ifndef U1A3UND4HEADER__H
    #define U1A3UND4HEADER__H
    
    class matrix
    {
    private:
    	int n, m;
    	int** feld;
    
    public:
    	matrix(int n, int m);
    	~matrix();
    	void print(int n, int m);
    	void input();
    	int getVal();
    };
    
    #endif
    
    #include<iostream>
    #include"U1A3und4header.h"
    using namespace std;
    
    matrix::matrix(int n, int m) : n(n), m(m)
    {
    	int** feld = new int*[n] ();
    
    	//Array allokieren
    	for(int i = 0; i<n ; i++)
    	{
    		feld[i] = new int[m] ();
    	}
    }
    
    matrix::~matrix()
    {
    	for (int j=0; j<n ; j++)
    	{
            delete[] feld[j];
    	}
    
    	delete[] feld;
    }
    

    Die "getVal"-Methode hab ich nun nochmal gelöscht. Mir fällt nämlich jetzt schon auf, dass der Destruktor den gleichen Fehler wie die getVal-Methode bringt.

    Ich denke ein Fehler liegt dann wohl schon am Anfang beim allokieren...

    Helft ihr mir?



  • bandchef: Du initialisierst in deinem Konstruktor eine lokale Variable feld und nicht die gleichnamige Membervariable. Dadurch erzeugst du einerseits ein Speicherloch, da der allozierte Speicher niemals freigegeben wird, und andererseits bleibt die Membervariable feld uninitialisiert, so dass es beim Zugriff darauf zu undefiniertem Verhalten kommt.

    Was SeppJ sagt, gilt natürlich trotzdem, das ist aber anscheinend nicht die direkte Ursache für dein Problem.



  • NATÜRLICH!

    Jetzt fällts mir auch auf! Nur wie kann ich auf das Feld in der Klasse zugreifen?

    Edit: So richtig?

    matrix::matrix(int n, int m) : n(n), m(m)
    {
    	this->feld = new int*[n] ();
    
    	//Array allokieren
    	for(int i = 0; i<n ; i++)
    	{
    		this->feld[i] = new int[m] ();
    	}
    }
    


  • ...



  • Ich will hier nun eine Methode Coden für eine Matrixmultikplikation. Ich hab auch schon wieder Code dafür:

    void matrix::mul(matrix feldLinks, matrix feldRechts)
    {
    	for (int i=0; i<this->m; m++)	//Zeilen durchschalten
    	{
    		for (int j=0; j < this->n; j++)		//Spalten durchschalten
    		{
    			for (int inner = 0; inner<this->n; inner++)		//Multiplizieren
    			{
    				this->feld[i][j] = this->feld[i][j] + (feldLinks.getVal(i, inner) * feldRechts.getVal(i, j));
    			}
    		}
    
    		cout << endl;
    	}
    }
    

    Die Klasse sieht nun mittlerweile so aus:

    class matrix
    {
    private:
    	int n, m;
    	int** feld;
    
    public:
    	matrix(int m, int n);
    	~matrix();
    	void print();
    	void input();
    	void mul(matrix feldLinks, matrix feldRechts);
    	int getVal(int m, int n);
    	void setVal(int m, int n, int val);
    };
    

    Die main Aufrufe hab ich so gemacht:

    matrix matrixLinks(3,3), matrixRechts(3,3), matrixErgebnis(3,3);
    
    	matrixLinks.input();
    	matrixRechts.input();
    	matrixErgebnis.print();
    
    	matrixErgebnis.mul(matrixLinks, matrixRechts);
    	matrixErgebnis.print();
    

    Problem daran ist nun, dass nach dem Aufruf der vorletzten Zeile in der main das Programm augenblicklich ohne Warnung stehen bleibt. Der Compiler kompiliert fehlerfrei! Was könnte das sein? Riecht irgendwie nach Endlosschleife...



  • ich würde zunächst mal die Membervariablen umbenennen, damit sie anders heißen, als die gleichnamigen Funktionesparameter

    int n, m;
    

    wenn der Compiler da keinen Drehwurm bekommt, bekommt ihn der menschliche Leser



  • wenn der Compiler da keinen Drehwurm bekommt

    Ne, der bekommt gar nix.

    ich würde zunächst mal die Membervariablen umbenennen, damit sie anders heißen, als die gleichnamigen Funktionesparameter

    😮
    Wohl eher andersrum!



  • um herauszufinden, ob der Compiler da einen Drehwurm bekommt, siehe ISO/IEC 14882:2011 3.4 Name lookup S. 45-59 (sind nur ca. 14 Seiten zu durchforsten 😉 )



  • ...



  • bandchef schrieb:

    void matrix::mul(matrix feldLinks, matrix feldRechts)
    {
      for (int i=0; i<this->m; m++)	//Zeilen durchschalten
      ...
    }
    

    m++?



  • Swordfish schrieb:

    Wovon soll da irgendwer 'nen Drehwurm bekommen?!

    in diesem Konstruktor

    matrix::matrix(int n, int m) : n(n), m(m)
    

    gelten folgende Regeln:

    3.4.1 Unqualified name lookup
    11 During the lookup for a name used as a default argument (8.3.6) in a function parameter-declaration-clause or used in the expression of a mem-initializer for a constructor (12.6.2), the function parameter names are visible and hide the names of entities declared in the block, class or namespace scopes containing the function declaration. [ Note: 8.3.6 further describes the restrictions on the use of names in default arguments. 12.6.2 further describes the restrictions on the use of names in a ctor-initializer. —end note ]
    12.6.2 Initializing bases and members
    2 In a mem-initializer-id an initial unqualified identifier is looked up in the scope of the constructor’s class and, if not found in that scope, it is looked up in the scope containing the constructor’s definition. [ Note: If the constructor’s class contains a member with the same name as a direct or virtual base class of the class, a mem-initializer-id naming the member or base class and composed of a single identifier refers to the class member. A mem-initializer-id for the hidden base class may be specified using a qualified name. —end note ] Unless the mem-initializer-id names the constructor’s class, a non-static data member of the constructor’s class, or a direct or virtual base of that class, the mem-initializer is ill-formed.
    12 Names in the expression-list or braced-init-list of a mem-initializer are evaluated in the scope of the constructor for which the mem-initializer is specified. [ Example:
    class X {
    int a;
    int b;
    int i;
    int j;
    public:
    const int& r;
    X(int i): r(a), b(i), i(i), j(this->i) { }
    };
    initializes X::r to refer to X::a, initializes X::b with the value of the constructor parameter i, initializes X::i with the value of the constructor parameter i, and initializes X::j with the value of X::i; this takes place each time an object of class X is created. —end example ] [ Note: Because the mem-initializer are evaluated in the scope of the constructor, the this pointer can be used in the expression-list of a mem-initializer to refer to the object being initialized. —end note ]

    in der mem-initializer-list im Konstrukor kann der Compiler also n und n noch auseinanderhalten, aber spätestens hier ist dann der Wurm drin:

    void print(int n, int m);
    

    der Compiler führt das dann zwar aus, aber es ist besser, die Member n und m anders zu benennen als die Funktionsparameter, denn in der Funktion print sind die Member n und m hidden und es geschehen merkwürdige Dinge



  • ...



  • Noch einmal: Da ist für den Compiler alles völlig klar.

    Und auch für den C++-Programmierer: Denn die Faustregel ist: Zuerst werden in inneren, und dann in äußeren Scopes gesucht. Und in der Initialisierungsliste lässt sich anhand der Syntax und logischen Gegebenheiten (wie der, dass Funktionsparameter nicht in der Initialisierungsliste "initialisiert" werden können) eben die jeweiligen Namen deduzieren.



  • ihr würded also empfehlen, die Benennung der Member und Funktionsparameter beizubehalten?

    class matrix
    {
    private:
        int n, m;
        int** feld;
    
    public:
        matrix(int n, int m);
        ~matrix();
        void print(int n, int m);
        void input();
        int getVal(int n, int m);
    };
    


  • ihr würded also empfehlen, die Benennung der Member und Funktionsparameter beizubehalten?

    Wir haben gar nix empfohlen und auch nichts suggeriert. Ich würde beispielsweise, tatsächlich um ein schnelleres Verstehen des Codes zu fördern, die Funktionsparameter mit Unterstrichen o.ä. entsprechend Kennzeichnen. Wichtig ist, dass man diesen Stil dann konsequent beibehält.


Anmelden zum Antworten