Referenz Wert verschwindet



  • Hallo mal wieder 🙄 ^^
    Es fängt an mit einem Konstruktor:

    Aircraft* player = new Aircraft(textureHolder, Aircraft::TYPE_EAGLE);
    

    Der so aussieht:

    Aircraft(const TextureHolder& textureHolder, const Aircraft::Type& type)
        :	mType(type),
    	mSprite(textureHolder.getResource(toTextureID(type)))
    {
    
    }
    

    toTextureFunktion:

    const Textures::ID& Aircraft::toTextureID(const Aircraft::Type& type)
    {
    	switch(type)
    	{
    	case Aircraft::Type::TYPE_EAGLE:
    		return Textures::ID_EAGLE;
    		break;
    	case Aircraft::Type::TYPE_RAPTOR:
    		return Textures::ID_RAPTOR;
    		break;
    	}
    }
    

    Bis hier hin geht auch alles gut.
    Nur bekommt der Parameter Identifier in der Funktion getResource aus der
    Klasse ResourceHolder einen Irrsinnigen wert wie 01A83912, obwohl es sich in meinem Fall um ein enum handelt. 😮

    template <typename Identifier, typename Resource>
    const Resource& ResourceHolder<Identifier, Resource>::getResource(const Identifier& id) const
    {
    	std::cout<<id;
    	// Search fro the key
    	auto found = mResourceMap.find(id);
    
    	// If not found give a error message
    	assert(found != mResourceMap.end());
    
    	// Else return the resource
    	return *found->second;
    }
    

    Warum geht das nicht (ich denke es hat irgendwas mit einem abgelaufenem Namensraum zu tun, aber ich finde den Logik Fehler nicht)?



  • Du übergibst dem Airplane Airplane::TYPE_EAGLE.
    In der toTexture prüfst du, ob das entweder Airplane::Type::TYPE_EAGLE und Airplane::Type::TYPE_RAPTOR. Airplane::TYPE_EAGLE ist weder das eine, noch das andere. Fazit: "zufälliger" return Wert.
    Btw: Die obligatorische Frage: Wieso new? Und wenn new sein muss, wieso ohne Smartpointer?



  • abgelaufenem Namensraum

    Was bitte soll denn das sein?

    obwohl es sich in meinem Fall um ein enum handelt

    Wie sieht die Definition der Enumeration aus? Das würde mich interessieren.

    Und mach mal aus

    std::cout<<id;
    das hier:
    std::cout << "\nID: " << id << '\n';
    

    Fazit: "zufälliger" return Wert.

    Das gibt's ja gar nicht. Wenn ein return -Statement fehlt, dann crasht das Programm (zumindest bei mir) an dieser Stelle (abgesehen davon, dass es sowieso UB ist).



  • Nathan, die zusätzliche Qualifizierung ist egal. Weißt du, wie Enumeratoren qualifiziert werden können?

    struct Airplane
    {
        enum Type
        {
            A, B
        };
    };
    
    int main()
    {
        Airplane::Type a = Airplane::A;
        Airplane::Type b = Airplane::Type::B;
    }
    


  • Ich erhalte beim gcc bei ints den Wert 1 als Rückgabe, bei doubles NaN.
    Auf einem anderen Compiler waren das aber durchaus zufällige Werte.

    Edit: Das ist mir klar.
    Aber die einzige offensichtliche Erklärung wäre, dass es zwei komplett verschiedene enums gibt (vielleicht um etwas verschiedenes auszudrücken? Updatefehler*?), und der TE das veraltete/falsche genommen hatte. Die andere Erklärung wäre, dass sein Hantieren mit rohen Pointern schief geht und er den return Wert überschreibt.

    *Mir schonmal passiert... Da hatte ich zwei verschiedene inkompatible structs.



  • Ich erhalte beim gcc bei ints den Wert 1 als Rückgabe, bei doubles NaN.
    Auf einem anderen Compiler waren das aber durchaus zufällige Werte.

    Wat? Bei mir stürzten bisher alle GCCs ab. Fehlende return-Statements sollten nicht einfach in willkürlichen Rückgabewerten resultieren.

    Aber die einzige offensichtliche Erklärung wäre

    Ja, die einzig offensichtliche 🙂
    Obwohl du schon Recht hast, das könnte sogar sein.



  • Frage: Ist diese Funktion gültig?

    const int& f()
    {
      return 0;
    }
    

    Antwort: Nein. Syntaktisch schon, aber sie macht null Sinn. Vernünftige Compiler geben da etwas in der Art von "warning: returning reference to local temporary object" aus.

    Kontext: Deine Funktion macht etwas analoges.

    Regel: Nie Referenzen zurückgeben, ausser es ist garantiert, dass die Referenz mindestens so lange lebt, wie das Objekt selber.

    Ich würde schreiben

    Textures::ID Aircraft::toTextureID(const Aircraft::Type& type)
    {
        switch(type)
        {
        case Aircraft::Type::TYPE_EAGLE:
            return Textures::ID_EAGLE;
        case Aircraft::Type::TYPE_RAPTOR:
            return Textures::ID_RAPTOR;
        default:
            assert(false);
        }
    }
    

    Sone schrieb:

    Aber die einzige offensichtliche Erklärung wäre

    Ja, die einzig offensichtliche 🙂

    Kinder, ihr seit echt unerträglich.



  • Kontext: Deine Funktion macht etwas analoges.

    Der Enumerator ist doch nicht lokal. Moment, du hast Recht! Wie das?



  • ongsthrtr schrieb:

    Sone schrieb:

    Aber die einzige offensichtliche Erklärung wäre

    Ja, die einzig offensichtliche 🙂

    Kinder, ihr seit echt unerträglich.

    Verdammt, das & übersehen. 😃



  • Sone schrieb:

    Moment, du hast Recht! Wie das?

    Enum-Member sind wie Literale. Die haben keine Adresse.



  • Wahnsinn, wusste ich gar nicht.



  • Kla gut, in dem fall wäre es egal, ob man ein enum mit oder ohne Refernz zurück gibt, aber im Falle das ich das mal mit viel Größeren Typen mache würde ich schon gerne wissen, wie ich das mit den Referenzen hinbekomme....
    Es sind defenitif die selben enum´s.
    Und ich erkenne keinen Logik Fehler, wo ein Referenz abgelaufen ist.

    enum Type
    	{
    		TYPE_EAGLE,
    		TYPE_RAPTOR,
    	};
    
    namespace Textures
    {
    	enum ID
    	{
    		ID_DESERT,
    		ID_EAGLE,
    		ID_RAPTOR,
    	};
    }
    


  • Aber mal ein schönes Beispiel, wie sehr man auf häufige Fehler geschult ist.
    Mir ist ein Fehler wegen einer Umbennung von etwas schon einmal passiert, deswegen ist mir das aufgefallen.
    Das mit der Referenz zu Temporary ist mir hingegen noch nie passiert (wie auch, Compilerwarnung), weswegen ich gar nicht auf so etwas geachtet habe.
    Faszinierend, wie unser Gehirn arbeitet.



  • Aber was macht man, wenn man mit Großen objekten Arbeitet?
    Wenn ich jetzt als ID zum Beispiel String habe, dann müsste der ja in der Funktion toTexture einen kompletten String zurückgeben...



  • Das ist gar nicht das Problem. Ich dachte, Enums sind einfach Konstanten, genauso wurde das auch immer erklärt... semantisch äquivalent zu einer Deklaration von Konstanten des underlying_type s... dass sie prvalues sind, und nicht const lvalues, ist ja krass.



  • DuffCola schrieb:

    Aber was macht man, wenn man mit Großen objekten Arbeitet?
    Wenn ich jetzt als ID zum Beispiel String habe, dann müsste der ja in der Funktion toTexture einen kompletten String zurückgeben...

    Gib alles by value zurück. Der Compiler kann das optimieren. copy elision, named return value optimization, etc. Vertrau einfach darauf. Und wenn du in einem konkreten Fall nicht sicher bist, frag im Forum nach.



  • DuffCola schrieb:

    Aber was macht man, wenn man mit Großen objekten Arbeitet?
    Wenn ich jetzt als ID zum Beispiel String habe, dann müsste der ja in der Funktion toTexture einen kompletten String zurückgeben...

    Ja, dann muss die Funktion halt einen kompletten String zurückgeben.
    Aber der Compiler kann da schon massig optimieren, mach dir da mal keine Sorge.



  • Also ich habs gerade nochmal getestet, wenn ich eine Kopie in der to Texture Funktion zurückgebe geht alles wunderbar.
    Gibt es wirklich keine andere Lösung ?

    Könnte ich vielleicht statt extra eine Funktion toTexture zu machen die Switch anweisung direkt im Konstruktor machen?



  • DuffCola schrieb:

    Also ich habs gerade nochmal getestet, wenn ich eine Kopie in der to Texture Funktion zurückgebe geht alles wunderbar.
    Gibt es wirklich keine andere Lösung ?

    Was ist denn das Problem!?

    Könnte ich vielleicht statt extra eine Funktion toTexture zu machen die Switch anweisung direkt im Konstruktor machen?

    Du willst doch den Konstruktor von mSprite in der Initialisierungsliste aufrufen, nein, dann musst du das offensichtlich auslagern.



  • Was ist denn das Problem!?

    Dass, wenn ich ein Großen Typ als id benutze, die toTexture funktion einmal ein großes Objekt kopieren muss.
    Kla ist es jetzt in diesem Fall egal, trotzdem würde ich gerne ein Lösung, die ohne Kopieren funktioniert.



  • DuffCola schrieb:

    Was ist denn das Problem!?

    Dass, wenn ich ein Großen Typ als id benutze, die toTexture funktion einmal ein großes Objekt kopieren muss.

    Und weiter? Wie wäre es, sich darüber Gedanken zu machen wenn es soweit ist?

    Kla ist es jetzt in diesem Fall egal, trotzdem würde ich gerne ein Lösung, die ohne Kopieren funktioniert.

    Wieso? Der Compiler kann viel optimieren. Darüber musst du dir keine Gedanken machen.


Anmelden zum Antworten