Help: std::queue destructor - AccessViolation



  • Hallo alle, ich bin neu hier, und auch recht neu in C++.

    Hier ist die Funktion, die mir probleme macht:

    void PushPolyFromStr(char* str) {
    	std::queue<char*> pointers;
    
    	unsigned short n=1;
    	//loop through all characters. Add pointers of all vertex coordinates into stack
    	pointers.push((char*)str);
    
    	while (char(*(++str))!= NULL) {
    		if (*str==';') { 
    			*str=char(NULL);
    			pointers.push(++str); 
    			n++;
    		};
    	}
    
    	TMyPoly* buf = new TMyPoly(n);
    
    	for(; n>0; n--) {
    		buf->Vertices[n-1]=Vertices.AddVertex(VertexFromStr(pointers.front()));
    		pointers.pop();
    	}
    
    	Polygons.AddPoly(buf);
    
    }
    

    Meistens funkzioniert es, aber.. Manchmal aber, beim rausgehen der funktion, passiert ein accessviolation fehler.

    Hier ist der callstack bei dem Fehler:

    > graph.exe!operator delete(void * pUserData=0xfeeefeee) Line 52 + 0x3 C++
    graph.exe!std::allocator<char *>::deallocate(char * * _Ptr=0xfeeefeee, unsigned int __formal=4) Line 132 + 0x9 C++
    graph.exe!std::deque<char *,std::allocator<char *> >::_Tidy() Line 957 C++
    graph.exe!std::deque<char *,std::allocator<char *> >::clear() Line 800 C++
    graph.exe!PushPolyFromStr(char * str=0x0012f5d0) Line 139 C++

    aus irgend-einen grund, versucht also der allocator daten zu löschen, die ohnerhin schon gelöscht sind.
    Was genau das Fehler auslöst (warum einiege inputs gehen, aber einiege nicht) konnte ich bisher nicht rausfinden.

    Arbeite ich mit der queue falsch? Was passiert da?

    Großen Dank im voraus! Wenn weitere Informationen nötig sind - sagt was, ich kopiere es.



  • Ach ja, ich arbeite mit MS Visual C++ 2003



  • Hallo Maverick,

    Die Benutzung der std::queue ist meiner Meinung nach korrekt. Poste doch bitte die Signatur des Konstruktors von TMyPoly - ist sichergestellt, dass Du 'n' dort nicht veränderst?

    Abgesehen davon empfehle ich aber die Variable 'n' nicht zur Verwaltung der Anzahl der Elemente zu nutzen. Das kann doch jeder STL-Container allein. Also etwa so:

    void PushPolyFromStr(char* str) {
        std::queue<char*> pointers;
    
        //loop through all characters. Add pointers of all vertex coordinates into stack
        pointers.push((char*)str);
    
        while (char(*(++str))!= NULL) {
            if (*str==';') {
                *str=char(NULL);
                pointers.push(++str);
            };
        }
    
        TMyPoly* buf = new TMyPoly( pointers.size() );
    
        for( int idx = 0; !pointers.empty(); ++idx ) {
            buf->Vertices[idx] = Vertices.AddVertex(VertexFromStr(pointers.front()));
            // evt. besser: buf->Vertices.push_back( .. );
            pointers.pop();
        }
    
        Polygons.AddPoly(buf);
    }
    

    .. aber das löst wahrscheinlich NICHT Dein Problem;es macht den Code aber gegen versehentliche Fehler robuster.

    Gruß
    Werner



  • Jo, die Korrektur übernehme ich danke 🙂

    Hier ist der TMyPoly Struct:

    struct TMyPoly {
    	unsigned short count;   
    	unsigned short* Vertices;  //Pointer to an array
    
    	TMyPoly() { TMyPoly::Vertices=NULL; TMyPoly::count=0; }; 
    	TMyPoly(unsigned short n) { TMyPoly::count=n; TMyPoly::Vertices = new unsigned short[n]; };
    	~TMyPoly() { delete[] TMyPoly::Vertices; }; 
    
    	bool exists(unsigned short v) {
    		for (unsigned short i=0; i<count; i++) {
    			if (Vertices[i]==v) return true;
    		}
    		return false;
    	}
    
    	inline unsigned short operator[] (unsigned short i) { return TMyPoly::Vertices[i]; };
    };
    

    Hm, ich habe gerade was interessantes entdeckt: ich habe das Compiller auf Multi-Threaded Debug umgeschaltet (das program ist console, Single-Threaded Debug war früher), und das Fehler war wo anderes 😮 Ich bin gerade weiter am debuggen, falls ich eine lösung doch finde - sage ich.



  • OK, hat sich erledigt: das Fehler war ein Memory-leak in AddPoly(buf).
    Weiß nicht, warum der Single-Thread-Debug so einen Callstack gezeigt hat..

    Danke!



  • Maverick89 schrieb:

    Hier ist der TMyPoly Struct:

    struct TMyPoly {
    	unsigned short count;   
    	unsigned short* Vertices;  //Pointer to an array
    
    	TMyPoly() { TMyPoly::Vertices=NULL; TMyPoly::count=0; }; 
    	TMyPoly(unsigned short n) { TMyPoly::count=n; TMyPoly::Vertices = new unsigned short[n]; };
    	~TMyPoly() { delete[] TMyPoly::Vertices; }; 
    
    	bool exists(unsigned short v) {
    		for (unsigned short i=0; i<count; i++) {
    			if (Vertices[i]==v) return true;
    		}
    		return false;
    	}
    
    	inline unsigned short operator[] (unsigned short i) { return TMyPoly::Vertices[i]; };
    };
    

    Hallo Maverick,

    bei der Klasse TMyPoly fehlt noch der Copy- und der Zuweisungsoperator. Diese sind genau dann notwendig, wenn Du einen nicht trivialen Destruktor hast und das ist mit

    ~TMyPoly() { delete[] TMyPoly::Vertices; };
    

    in Deinem Fall gegeben. Das nennt man 'Rule of three'.
    Schreibe z.B. folgenden Code:

    {
        TMyPoly a(8);
        TMyPoly b( a );   // möglich, da Copy-Konstruktor automatisch generiert wird
    }  // <- von a UND b wird der Destruktor gerufen -> Crash; da 2mal delete <gleiche Speicheradresse>
    

    Wenn Du Dir die Mühe nicht machen willst, so setze den Copy- und Zuweisungsoperator private - also:

    struct TMyPoly {
    	unsigned short count;  
            // usw. 
    private;
        TMyPoly( const TMyPoly& );
        TMyPoly& operator=( const TMyPoly& );
    };
    

    .. dann läßt sich mein Crash-Beispiel nicht übersetzen und der Compiler nennt Dir die kritische Stelle, bevor Du sie mühsam mit dem Debugger suchen musst.

    Gruß
    Werner



  • Ja, dass habe ich schon korrigiert.
    Das problem lag aber auch daran, dass ich dass dynamische array immer per memcpy() kopiert habe, und das copy-constructor deswegen nicht neu aufgerufen wurde, destructor am ende der funktion aber schon.

    Danke 🙂


Anmelden zum Antworten