Ruft map::erease den Destruktor auf?



  • Ein anderes Problem: folgender Code:

    this->p_Server->mConnections.erase(GetCurrentThreadId());
    

    Funktioniert bei mir bei der normalen Ausführung nur 1 mal, beim 2. mal nicht mehr, und beim Debugging crasht das Proggy gleich beim ersten mal(Visual C++ zeigt an, dass er in der Funktion equal_range() crasht).
    Das zu löschende Objekt existiert 100% prozentig(hab die Thread-IDs vorher 2 mal(1 mal beim anlegen des Objektes und 1 mal vor dem entfernen) ausgeben lassen und sie sind identisch).



  • also: erase löscht ALLE elemente zu dem key (bei multimaps kann es ja zu einem schlüssel mehrere elemente geben).
    du verwendest vermutlich aber ne stl::map, sprich ein key->ein element.
    dabei ist erase unkritisch.
    mach doch mal folgendes:

    std::cout<<this->p_Server->mConnections.erase(GetCurrentThreadId())<<std::endl;
    

    dann siehst du ob prinzipiell ein element gefunden wurde.
    der Fehler wird so wie es aussieht nichts mit der map zu tun haben, sondern mit den darin enthaltenen "threads".



  • Der "Fehler" besteht darin, dass das Programm mit dem Aufruf der Funktion crasht...



  • Gib mal ein bisschen Kontext.
    Davon abgesehen: wenn erase crasht ... dann wirds wohl gröber was haben. erase selbst kann man eigentlich nicht mit Parametern füttern die zu einem Absturz führen könnte, d.h. höchstens die Destruktoren die dann laufen könnten den Absturz verursachen, oder er ist evtl. schon verursacht worden bevor erase läuft, Speicher überschrieben oder sowas.

    Andere sache: da du offensichtlich mit Threads arbeitest: synchronisierst du auch brav alle Zugriffe auf diese map (und andere gemeinsam genutzte Daten)?



  • Also, ich schreib grad eine Art "Server-Engine", in der alle Verbindungen und der ganze socket-Kram in einer Klasse gemanaged werden. Die einzelnen Verbindungen werden wiederrum in einer eigenen Klasse gemanaged. Die ganzen Verbindungen werden dann in einer Map abgelegt und als Index dient die Thread-ID des Threads, der für die Verbindung "zuständig" ist. Nun wird, wenn Thread, der zuständig ist, "fertig" ist, die Verbindung dazu über delete connection; gelöscht. Im Destruktor von connection wiederrum trägt sich die Verbindung eigenhändig aus der Sammel-Map vom Server aus.
    Das komische ist jetzt, dass das ganze bei der 1. Verbindung problemlos funzt und bei der 2. Verbindung bis vor mConnections.erase() im Destruktor kommt(vor map::erase funktioniert noch eine Ausgabe mit printf).

    Wegen der Synchronisierung: so wie der Code gebaut ist, kommen nie ein 2 Zugriffe gleichzeitig zustande.

    Edit: Hab grad rausgefunden, dass map::erase bei 1. mal zwar nicht crasht aber auch nich die Verbindung löscht.



  • Hi,

    kenne mich damit nicht besonders gut in dem Thema aus, aber: Bist Du sicher, dass diese "Connections" das Kopieren überstehen ? Immerhin wird in eine map hinein und "drin herum" einiges kopiert ...

    Gruß,

    Simon2.



  • Die Map sieht so hier aus:

    map<unsigned long, IServerConnection*> mConnections
    

    ➡ Da drin gibt es nur Pointer auf die Connections. Das komische ist ja, dass alles einwandfrei funktioniert, nur das löschen nicht.



  • Steht this->p_Server->mConnections.erase(GetCurrentThreadId()); in dem Destruktor, von Connection der aufgerufen wird, wenn du delete connection machst? (ich nehme mal an ja, aber möchte sicher gehen, dass ich deine funktionsweise richtig verstanden hab).

    Hat IServerConnection einen virtuellen Destruktor?

    Wenn das Löschen nicht funktioniert, dann liegt das aber definitiv nicht an der map, weil hier nur mit einfachen Typen gearbeitet wird und nicht mit deinen Objekten. Ich vermute daher stark, dass der Speicher bis zum Löschen schon längst nicht mehr gültig ist und es deshalb zum Absturz kommt (dass es im Debugger direkt crasht spricht ebenfalls stark dafür).

    Zeigt this->p_server auch ganz sicher auf gültigen Speicher (schau mal im Debugger)?

    Ist this bzw. das connection-Objekt bei dem delete connection Aufruf auch nur wirklich existent?

    Auch wenn (theoretisch) keine 2 Zugriffe auf die map statt finden können, pack die Zugriffe da doch zur Sicherheit mal in ne critical section um auch ganz sicher zu gehen, dass es das wirklich nicht ist.



  • Verdammt bin ich blöd! 😮
    Ich hab in jeder den beiden Klassen(Connection und Instance Template) folgendes stehen:

    friend IServer;
        IServer* p_Server;
    

    Hab aber den Pointer für p_Server nur beim Instance Template mitgegeben und bei der Connection völlig vergessen.
    Vielen Dank für den Denkanstoß!

    Nochmal wegen der Synchronisierung: werd ich noch machen, nicht dass ich dann wieder mit so nem dummen Problem hierher gerannt komme 😃 .



  • Dr. C++ schrieb:

    Die Map sieht so hier aus:

    map<unsigned long, IServerConnection*> mConnections
    

    ...

    Ok, das wusste ich nicht.

    Gruß,

    Simon2.


Anmelden zum Antworten