Referenz Wert verschwindet



  • 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.



  • Sone schrieb:

    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!?

    Eben.
    Selbst wenn der Compiler die Optimierung nicht macht, ints (nichts anders sind enums) zu kopieren, macht der Computer im Schlaf, das geht so schnell.

    Aber beschäftige dich nicht so sehr mit Geschwindigkeit:

    Es ist viel einfacher ein korrektes Programm schnell zu machen, als ein schnelles Programm korrekt.

    We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil

    Denk einfach nicht drüber nach, optimiere erst wenn du einen Grund hast und dann dort, wo es wirklich nötig ist (Profiler!)
    Und erst recht nicht in der Rückgabe von ints!
    Wenn du optimieren musst, dann ersetz deine Map in ResourceHolder durch einen Hashtable oder einen sortierten Vektor, das bringt viel mehr.

    PS: Jetzt sag nicht, du verwendest aus diesem Grund auch keine Smart Pointer. 🙄



  • 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.

    Wenn du unsere Posts gelesen hättest, wüsstest du, dass das nicht stimmt.


Anmelden zum Antworten