[Solved] Alle Membervariablen sind bei einem bestimmten Memberfunktionsaufruf korrupt



  • Hallo allerseits,

    Folgendes struct übergebe ich von einer Klasse an eine andere, und "cache" es als Membervariable, da die Daten erst später während eines update() Vorgangs gebraucht werden:

    struct SpawnPoint {
        sf::Vector2f position;
        float rotation;
    };
    // ...
    
    // In Aktion:
    
    // Eine Klasse übergibt den SpawnPoint an weapon über die Funktion fire_if_ready
    weapon.fire_if_ready({ world_position(), getRotation() });
    // ...
    class Weapon {
    // ...
        void fire_if_ready(const SpawnPoint&);
        void create_projectile(..., const TextureHolder& textures /* jetzt hier */);
    private:
        Command fireCommand;
        SpawnPosition nextSpawnPosition;  // fire_if_ready kopiert hier die Daten hinein
        // const TextureHolder& textures;
    

    Der Haken ist, dass in nextSpawnPosition nur Müll steht, sobald ich die Daten brauche (im Debug Build eine große negative Zahl, -1073...).

    Ich habe eine sehr starke Vermutung, dass folgendes ein Problem ist, weil ich zuvor mit einer anderen Membervariable Probleme hatte, nämliche einen const TextureHolder& . Dieser war an der selben Stelle "korrupt", wo jetzt auch der SpawnPoint korrupt ist. Ich hatte in dem Fall den TextureHolder als Argument an den Callback ( fireCommand.action ) übergeben, um das Problem zu umgehen (welches ich nicht verstehe):

    struct Command {
    	using Action = std::function<void(SceneNode&, sf::Time)>;	
    	Action action;
    	unsigned category{};
    };
    // ...
    Weapon::Weapon(Type t, const TextureHolder& texts):
    	type{ t }, 
    	ammo{ Table[t].ammo },
    	cooldown{ Table[t].cooldown }
    {
    // begin ********************************
    	fireCommand.action = [this, t, &texts](SceneNode& node, sf::Time) {
    		create_projectile(node, Table[t].projectile, {}, texts /* jetzt hier */);
    	};
    // end ********************************
    // ...
    void Weapon::create_projectile(...)
    {
        // hier sind nextSpawnPoint und andere Membervariablen korrupt, weil ich wohl etwas falsch mache
        // angefangen hat es mit dem TextureHolder, aber dann habe ich diesen als Parameter übergeben und alles war ok
    }
    

    Das Problem Kind hier ist die create_projectile Funktion, hier sind die Membervariablen dann immer korrupt. Ich denke ich mache da etwas mit std::function etc. falsch, vielleicht sieht es jemand sofort.

    tl;dr In der Funktion create_projectile sind praktisch alle Membervariablen mit Müll befüllt, ich vermute der Fehler liegt in der oben im Code markierten Stelle. Ich verstehe jedoch das Problem nicht konkret 😕

    Ich habe mir echt Mühe gegeben das Problem exakt zu lokalisieren, aber ich sitze total auf dem Schlauch, bzw. vielleicht fehlt mir einfach das notwendige Wissen. Vielleicht erträume ich mir ja die Lösung 😃

    Ich freue mich über jede Antwort.

    LG



  • Wer soll aus den Codschnipseln irgendetwas erkennen?

    Ich vermute, dass du eine Referenz auf ein temporäres Objekt speicherst.



  • Welches Betriebssystem und Kompiler?



  • weiß nicht ob ich hier was übersehen habe aber du musst schon mindestens die ganze klasse "weapon" posten damit ich dir helfen kann.
    keine ahnung wie da der rest ausssieht.

    ansonsten kann ich erstmal jetzt so nichts erkennen was im gezeigten code das verhalten auslösen könnte.
    hast du evt. i.welche compilerwarnung? (diese aktiviert beim compilieren?)
    wenn ja post die mal...

    kann aber sein das ich was übersehen habe weil hab es nur schnell überflogen da eh die hälfte fehlt .

    bitte poste alles und ich schau nochmal ob ich was seh 🙂
    (evt hat manni auch schon die lösung gepostet 😉 )

    lg


  • Mod

    manni66 schrieb:

    Wer soll aus den Codschnipseln irgendetwas erkennen?

    Ich vermute, dass du eine Referenz auf ein temporäres Objekt speicherst.

    Davon gehe ich auch aus.

    Weapon::Weapon(Type t, const TextureHolder& texts):
    //                                   ||
    //                                   \/
    	fireCommand.action = [this, t, &texts](SceneNode& node, sf::Time)
    

    Das Closureobjekt hält nur eine Referenz auf texts. Falls dieses aber auf ein temporäres Objekt verweist, ist dieses Objekt wahrscheinlich schon zerstört worden, wenn action irgenwann nach Verlassen des Weapon-Konstruktors mal aufgerufen wird.



  • Hallo miteinander,

    tut mir leid, dass ich so spät antworte, ich konnte nicht auf das Forum zugreifen.

    Es war mein Fehler, ich habe die Lokalität meines Problems falsch eingeschätzt, deshalb bringen meine geposteten Schnipsel tatsächlich nichts.

    Ich habe das Problem "gelöst", indem ich folgende Zeile geändert habe:

    weapons.push_back(Weapon{Weapon::Gun, textures});
    // ===>
    weapons.emplace_back(Weapon::Gun, textures);
    

    Hinweis war, dass ein Debugging Statement in ~Weapon() ausgeführt wurde, jedoch sollte das im Nachhinein ja auch so sein, denn ich nehme an push_back kopiert das Argument und der temporär erzeugte Weapon wird dann schließlich destructed.

    Jedenfalls schien mir "Objekt wird zerstört bevor es soll" und "alle Membervariablen sind Müll" zusammenhängend.

    Woran das alles jetzt liegt - keine Ahnung. Ich war am Ende auch zu genervt, um länger auf die Suche zu gehen.



  • Deine Klasse Weapon wird wahrscheinlich die dreier/fünfer/nuller Regel verletzen. Das wird dir recht schnell wieder Probleme machen.



  • manni66 schrieb:

    Deine Klasse Weapon wird wahrscheinlich die dreier/fünfer/nuller Regel verletzen. Das wird dir recht schnell wieder Probleme machen.

    Ich verwende eigentlich keine Ressourcen, welche nicht über RAII gemanaged werden. Ich wüsste also nicht, weshalb die Compiler-generierten Versionen nicht funktionieren sollten.

    Um es zu verdeutlichen: Ich brauche eigentlich keinen (expliziten) dtor - ich habe nur einen definiert nach dem Motto:

    ~Weapon() { std::cerr << "DESTROYED\n"; }
    


  • Solche Problem sind mit -fsanitize=address,undefined in zehn Sekunden gefunden und in den meisten Fällen in weiteren zehn Sekunden behoben.

    Woran das alles jetzt liegt - keine Ahnung. Ich war am Ende auch zu genervt, um länger auf die Suche zu gehen.

    Nun, der Fehler ist noch da und wird wiederkehren. Wenn du den Dingen nicht auf den Grund gehst und deine Programme wachsen, wirst du Programme haben, bei denen so viele Fehler fest ins Fundament einzementiert wurden, dass sie bei jeder Abweichung von der Norm oder einfach durch Zufall abstürzen oder sich anderweitig falsch verhalten - ohne Chance, das jemals wieder in den Griff zu bekommen.



  • @;Rohan Ich arbeite derzeit mit VC++, daher müsste ich wohl auf andere Tools zurückgreifen.

    Ich habe jetzt nochmal scharf nachgedacht, und mir kam eine Idee, weil beim emplace der Fehler 100% nicht auftritt, jedoch bei einem push_back 100% auftritt. Außerdem:

    Ich vermute, dass du eine Referenz auf ein temporäres Objekt speicherst.

    Kann es sein, dass bei der Erzeugung des temporären Weapons der std::function callback den this pointer auf das Temporäre Objekt captured, dann wird mit dem standard generierten copy-ctor jenes callback an das neue Objekt im vector übergeben, jedoch hat es noch den this pointer auf das temporäre Objekt, welches dann zerstört wurde? Das würde die Referenz auf ein temporäres Objekt erklären...

    In anderen Worten: Ich habe jetzt glaube ich kapiert was manni66/camper mit temporärem Objekt etc. meinen. Stellt sich die Frage, ob das jetzt ein Designfehler von mir ist, oder ich mich mit emplace_back zufrieden geben darf.


  • Mod

    HarteWare schrieb:

    Woran das alles jetzt liegt - keine Ahnung. Ich war am Ende auch zu genervt, um länger auf die Suche zu gehen.

    Schade. Das bedeutet wahrscheinlich, dass du den Fehler nicht beseitigt und eine Chance, etwas dabei zu lernen, vertan hast.



  • HarteWare schrieb:

    Stellt sich die Frage, ob das jetzt ein Designfehler von mir ist,

    Was sonst?

    oder ich mich mit emplace_back zufrieden geben darf.

    Wenn der Vector seine Größe ändert, wird durch kopieren oder verschieben zumindest this ungültig.



  • manni66 schrieb:

    HarteWare schrieb:

    Stellt sich die Frage, ob das jetzt ein Designfehler von mir ist,

    Was sonst?

    oder ich mich mit emplace_back zufrieden geben darf.

    Wenn der Vector seine Größe ändert, wird durch kopieren oder verschieben zumindest this ungültig.

    Stimmt, habe es soeben ausprobiert, gleich danach ein resize(500) , schon knallt es wieder. Ich werde mir etwas anderes überlegen müssen. Ich habe das von einem Design übernommen, wo Objekte in einem Graphen gespeichert sind. Funktioniert aber mit vector wohl nicht mehr.

    Vielen Dank für Eure Hilfe, zumindest ist es mir jetzt wie Schuppen von den Augen gefallen, was da schief läuft.


Log in to reply