Verlorene Addressen ...



  • Hallo zusammen,

    ich arbeite an einem Programm, das ein vorvernetztes FEM-Netz übernehmen und lokal-verfeinern soll. Dazu speichere ich die übergebenen Elemente und Zeiger auf deren Nachbarn, wenn vorhanden, in Form einer Klasse sourceQuad in eine STL-Liste. Die Klasse sieht, etwas abgespeckt, etwa so aus

    [code]
    class sourceQuad
    {
    public:
    
    	sourceQuad(const quad *source):
    	  mySource(source)
    	{
    		myTree = new splitTree(*(new element(*mySource, 1, 1)), count++, *this);
    	}
    
    	~sourceQuad(void)
    	{
    		count--;
    		delete myTree;
    	}
    
    // ... unter anderem
    
    	void SetNeighbours(sourceQuad *left, sourceQuad *right, sourceQuad *top, sourceQuad *bottom);
    
    	void findLeftNeighbour(sourceQuad *prev, std::list<int> *path, std::list<leaveNode> *neighbours);
    	void findRightNeighbour(sourceQuad *prev, std::list<int> *path, std::list<leaveNode> *neighbours);
    	void findTopNeighbour(sourceQuad *prev, std::list<int> *path, std::list<leaveNode> *neighbours);
    	void findBottomNeighbour(sourceQuad *prev, std::list<int> *path, std::list<leaveNode> *neighbours);
    
    private:
    	static unsigned int count;	// counter of source quadrilaterals
    
    	sourceQuad *myLeft;			// left neighbour of the source-quad
    	sourceQuad *myRight;		// right neighbour of the source-quad
    	sourceQuad *myTop;			// top neighbour of the source-quad
    	sourceQuad *myBottom;		// bottom neighbour of the source-quad
    
    	const quad *mySource;		// source quadrilateral
    
    	splitTree *myTree;			// quadtree of the quadrilateral
    };
    [/code]
    

    Da ich die Nachbarn zur Zeit der Erzeugung noch nicht weiß, setzt ich sie hinterher mit der Klassenmethode SetNeighbours, die folgendermaßen aussieht.

    [code]
    inline void sourceQuad::SetNeighbours(sourceQuad *left, sourceQuad *right, 
    					sourceQuad *top, sourceQuad *bottom)
    {
    	myLeft		= left;
    	myRight		= right;
    	myTop		= top;
    	myBottom	= bottom;
    }
    [/code]
    

    Die verfeinerten Unterelemente werden innerhalb der sourceQuad-Klasse in einem Quadtree gespeichert. Für eine "Discontinuous Gallerkin Berechnung" brauche ich jeweils die Nachbarelemente. Wenn ein Element sein Nachbarelement nicht innerhalb des Baumes findet, gelangt es zurück in die sourceQuad Klasse die es an das entsprechende Nachbarelement verweist. Dies geschieht im unten angegebenen Beispielcode für den Linken Nachbarn im ersten Teil der if-Anweisung.

    [code]
    inline void sourceQuad::findLeftNeighbour(sourceQuad *prev, std::list<int> *path, std::list<leaveNode> *neighbours)
    {
    	// check where the search comes form
    	if (prev == 0)				// search comes from the bottom
    		myLeft->findLeftNeighbour(this, path, neighbours);
    	else						// search comes from the top
    	{
    		// find out, where the search comes form
    		/*if (myRight == 0)
    			if (myRight == prev)*/
    				myTree->findLeftNeighbour(0, path, neighbours);      // <-- in dieser Zeile erfolgt die Zugriffsverletzung!!!
    	}
    }
    [/code]
    

    So, nun zum Problem. Im richtigen Nachbarelement angekommen, erkennt das Programm nun dass es den else-Zweig der if-Anweisung ausführen muss, stürzt aber dann mit einer Zugriffsverletzung ab. Im Debug-modus von VS ist dann ersichtlich, dass die Zeiger für die Nachbarn und den Baum nicht mehr gültig sind. Aber wie so? Die Nachbarn wurden doch als Zeiger übergeben und nicht mehr geändert, und der Baum wurde im Konstruktor, mit new auf dem Heap erzeugt. 😕

    Das Programm compiliert ohne Fehler- oder Warn-Meldungen.

    Hat jemand eine Idee wo das Problem liegen könnte? Suche schon seit längerer Zeit und bin mit meinem C++(Latein) am Ende. (Bin auch noch nicht so lange dabei, beim C++ programmieren meine ich)

    Wie könnte man es alternativ lösen?

    Herzlichen Dank für alle Ideen.

    Viele Grüße



  • Wenn die Klassen so stimmen, dürfte es ja gar nicht compilieren, da
    "myTree" als "splitTree" definiert ist, aber die Methode "findLeftNeighbour" in der Klasse "sourceQuad", so daß der Aufruf

    myTree->findLeftNeighbour(...)
    

    zu einem Fehler führen müßte (außer du hast auch in "splitTree" die Methode "findLeftNeighbour" definiert).

    Noch eine Anmerkung: bei STL-Klassen benutzt man besser Referenzen, anstatt Zeiger als Methodenparameter (ist besser lesbar), also z.B.

    typedef std::list<int> PathList;
    typedef std::list<leaveNode> NeighbourList;
    void findLeftNeighbour(const sourceQuad & prev, const PathList & path, const NeighbourList & neighbours) const;
    

    Außerdem das Schlüsselwort "const", um anzuzeigen, daß keine Veränderungen an der Klasse vorgenommen werden.



  • Danke für den Hinweis mit den "typedef"'s. Werde es sofort ändern.

    Ja es stimmt, dass auch in "splitTree" die Methoden findLeftNeighbour(...), etc. definiert sind, die zunächst festellen ob ein Nachbar im splitTree vorhanden ist, bevor die ensprechende "sourceQuad"-Methode aufgerufen wird. Die "splitTree"-Methoden füllen auch die "path"-Liste zum Ausgangselement, damit das Nachbar-"sourceQuad" weiß, in welche Richtung und wieviele Ebenen es nach unten muss, bzw. die sourceQuad-Methode sollte die Information lediglich and die splitTree-Methode weiterreichen und die sollte dann wissen wo sie hin soll.

    Sorry, dass diese Information nicht von Anfang an dabei war!!!



  • Entschuldigung aber ich muss das Thema leider nochmal aufmachen, da ich's leider immer noch nicht auf die Reihe bekommen habe.

    Ist es überhaupt zulässig in den privaten Elementen einer Klasse Zeiger auf Elemente der gleichen Klasse zu haben?

    class sourceQuad
    {
        // ...
    private:
        sourceQuad *myLeft;
        sourceQuad *myRight;
        // ... etc.
    };
    

    Muss ich diese dann gleich im Konstructor initialisieren oder kann ich die auch erst später belegen? Muss ich um so etwas machen zu können einen default-Konstructor haben?

    Irgendwie misstraue ich der im ersten post angegebenen SetNeighbour-function.

    Bin um jede Hife sehr, sehr, sehr dankbar.



  • Ist es überhaupt zulässig in den privaten Elementen einer Klasse Zeiger auf Elemente der gleichen Klasse zu haben?

    Ja.

    Muss ich diese dann gleich im Konstructor initialisieren oder kann ich die auch erst später belegen?

    Beides ist möglich. Wenn man von außen zugreifen möchte (nicht empfehlenswert) kann man Zugriffsfunktionen dafür bauen.

    Muss ich um so etwas machen zu können einen default-Konstructor haben?

    Nein


  • Mod

    Knecht schrieb:

    Muss ich diese dann gleich im Konstructor initialisieren oder kann ich die auch erst später belegen?

    du musst sie nicht bereits im konstruktor initialisieren - allerdings sind singuläre pointer eben leicht ein hindernis beim debuggen. es ist generell gute praxis, alle member einer klasse zu initialisieren.



  • Das hört sich ja so an, als ob der obige Code nicht ganz falsch ist (Hoffnung macht sich breit?!?). Hat jemand eine Idee was die Zugriffsverletzung dann verursachen könnte, bzw. wieso die anschließend gesetzten Zeiger nicht erkennt werden und vom Debugger als ungültig bezeichnet werden?


Anmelden zum Antworten