Smart Pointers und Maps

  • C/C++

Diese Seite verwendet Cookies. Durch die Nutzung unserer Seite erklären Sie sich damit einverstanden, dass wir Cookies setzen. Weitere Informationen

  • Smart Pointers und Maps

    Ich hoffe es wird sich hier ein findiger C++ guru finden der mir bei dem kleinen Problem helfen kann.

    Ich speichere Sound-ressourcen in einer Map (Als pointers). Der Code schaut in etwa so aus:

    Quellcode

    1. GMEXPORT double streamLoad(char * filename){
    2. if(emptyStreamIDs.empty() == false){//if there are still IDs available
    3. if(fexists(filename) == true){
    4. //loading new music
    5. std::string stringFilename(filename);
    6. OutputStreamPtr musicStream = OpenSound(device, stringFilename.c_str(), true);//Load Ressource (Pointer)
    7. //add to map
    8. std::set<int>::iterator it = emptyStreamIDs.begin();//get next free ID
    9. int streamID = *it;//get the content of the iterator and store it
    10. streamMap.insert(std::pair<int,OutputStreamPtr>(streamID,musicStream));// Insert Ressource into Map
    11. emptyStreamIDs.erase(streamID);//erases ID so it isn't available anymore
    12. return streamID;
    13. }else{
    14. return -3;//file doesn't exist
    15. }
    16. }else{
    17. //erlse return errorcode (all IDs are used up)
    18. return -2;
    19. }
    20. }
    Alles anzeigen


    Die wichtigsten stellen sind eben die erstellung des Smart Pointers und das hinzufügen zur map.
    Nun, wenn ich versuche ein Element aus der Map zu entfernen, crasht das Programm.
    Das ist der Code der das zum crashen bringt:


    Quellcode

    1. GMEXPORT double streamDelete(double ID){
    2. if(isStreamIDinRange((int)ID)){
    3. if(streamMap.count((int)ID) >= 1){//check if the key exists at all
    4. //stop if the stream is playing right now
    5. streamMap[(int)ID]->stop();
    6. //erase streamID
    7. std::map<int,OutputStreamPtr>::iterator it = streamMap.find((int)ID);
    8. streamMap.erase(it); ///<<<----- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Das hier bringt alles zum absturz.
    9. //add ID to the set-datastructure so it is available
    10. emptyStreamIDs.insert((int)ID);
    11. return 1;
    12. }else{
    13. return -1;
    14. }
    15. }else{
    16. return -1;
    17. }
    18. }
    Alles anzeigen


    Manchmal passiert es beim ersten aufruf, aber manchmal auch erst beim 2ten oder 3ten.
    Gibt es irgendeine Regelung mit (Smart)-pointern die ich noch nicht realisiert habe? Muss ich irgendetwas beachten wenn ich diese mit Datenstrukturen wie maps verwende? (Scoping, referenzen die irgendwo irgendwie noch erstellt werden, etc...)

    /Edit:
    Ok, ich bin dem Problem auf die schliche gekommen. Bei mir war der Code richtig. Die crashes wurden von Audiere ausgelöst.
    Wenn ich auf eine Ressource zugreife, kurz bevor sie dereferenziert wird kann ein Crash passieren.
    Audiere hat einen eigenen Thread der die Soundengine updated. Wenn ich einen Ressource verändere (z.B: diese Stoppe) wird der stop-befehl in eine Queue im Audiere Thread eingefügt.
    Nun, der Stop-befehl wird dadurch mit einer leichten verzögerung ausgeführt. (da ein anderer Thread dafür verantwortlich ist.)
    Wenn ich also nun dereferenziere (=das objekt wird gelöscht), könnte es sein dass der Stop-befehl in der Queue noch nicht abgearbeitet wurde.

    Wenn der Stop-befehl ausgeführt wird und das objekt nicht mehr existiert für das der Stop-befehl gedacht war dann crasht das ganze...

    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von LEWA ()

  • Dann locke solange bis die Engine das Event abgearbeitet hat.

    Aber generell ein paar Sachen:
    • streamMap.insert(std::pair<int,OutputStreamPtr>(streamID,musicStream)) ---> streamMap[streamID] = musicStream;
    • du wandelst den filename erst in einen std::string um und benutzt ihn dann als .c_str()? Sinn?
    • emptyStreamIDs wuerde ich evtl ne Queue benutzen, erspart dir codezeilen
    • streamMap.erase((int)ID); (btw...warum double? Will der GM das so?)
    • die "richtige" art zu schaun ob ein Element in der Map ist, ist: if((streamMap.find((int)ID) != streamMap.end()) { .... }
    Macht den Code uebersichtlicher, in etwa so:

    EDIT: audiere.sourceforge.net/audier…iere_1_1StopCallback.html sollte exakt das sein was du brauchst.

    Quellcode

    1. GMEXPORT double streamLoad(const char * filename) {
    2. if(emptyStreamIDs.empty() == true)
    3. return -2;
    4. if(fexists(filename) == false)
    5. return -3;
    6. //loading new music
    7. OutputStreamPtr musicStream = OpenSound(device, filename, true);//Load Ressource (Pointer)
    8. //add to map
    9. const int streamID = emptyStreamIDs.pop();
    10. streamMap[streamID] = musicStream; // Insert Ressource into Map
    11. }
    12. GMEXPORT double streamDelete(double ID) {
    13. const int id = (int)ID;
    14. if(isStreamIDinRange(id) == false)
    15. return -1;
    16. if(streamMap.find(id) == streamMap.end())
    17. return -1;
    18. //stop if the stream is playing right now
    19. streamMap[id]->stop();
    20. // !!--!! Hier jetzt auf die Verarbeitung des Events warten und dann loeschen. Oder den loesch part in nen callback werfen. Je nachdem wie du es brauchst.
    21. streamMap.erase(id);
    22. //add ID to the set-datastructure so it is available
    23. emptyStreamIDs.push(id);
    24. }
    Alles anzeigen

    Dieser Beitrag wurde bereits 4 mal editiert, zuletzt von rootnode ()

  • Danke auf jedenfall für die Tipps!

    streamMap.erase((int)ID); (btw...warum double? Will der GM das so?)

    Der GM kann nur doubles bzw strings an DLLs weitergeben.

    Hab das ganze letztlich auf ein Array umgeschrieben (was eigentlich ein resultat weiterer experimente war, aber naja... der code wurde wengistens verkleinert)

    Das Problem mit dem Error bin ich jetzt so umgangen, dass der GM die Streams erst nach 2-3 sekunden löscht. (Sie werden zum löschen markiert, die DLL stoppt dann den stream und nach 2-3 sekunden wird dieser gelöscht.)
    Ist natürlich ein sehr dürftiger workaround, aber da ich mich in C++ nicht wirklich auskenne muss diese Lösung vorerst reichen.