Liste mit Zeigern



  • stefan schrieb:

    Hmm ne eigenen Container hab ich mir noch nicht geschrieben. Aber ist das überhaupt so sinvoll sich da einen eigenne zu schreiben, gibts ja schon gute. Oder ist das mehr so zum verständnis dann gedacht? Nimmst du da einen selbstgeschriebenen her?

    Nein, mehr fürs Verständnis. Ich hab das auch mal gemacht und dabei recht viel gelernt (vor allem, was new und delete und Templates betrifft). Sollte nur so ein Beispiel sein, natürlich muss man das nicht zwingend einmal getan haben.
    Momentan verwende ich eigentlich nur Standardcontainer und ab und zu solche von Boost, aber eigentlich nie selbstgeschriebene.

    stefan schrieb:

    Naja werd mir wahrscheinlich doch auch mal ein Buch kaufen müssen. Was gibt es denn da gutes?
    Hab mal so geschaut und hab dann das gefunden:
    "C++ Für Spieele-Programmierer"

    Weißt wer ob das was ist oder gibt es da bessere Bücher?

    Das Buch kenne ich nicht, allerdings würde ich eher zu einem "reinen" C++-Buch raten. Das Spieleprogrammierer-Buch bindet dich wahrscheinlich an eine API (wenns blöd kommt, SDL, was eher kontraproduktiv für das Lernen von C++ ist) und vernachlässigt C++-Teile eher. Aber das ist nur meine Vermutung.

    Als C++-Buch wird oft der C++-Primer empfohlen. Ich habe sehr viel durch das C/C++-Kompendium von Dirk Louis gelernt. Wäre gut, wenn noch andere User ihre Empfehlungen abgeben könnten...



  • Das Buch kenne ich nicht, allerdings würde ich eher zu einem "reinen" C++-Buch raten. Das Spieleprogrammierer-Buch bindet dich wahrscheinlich an eine API (wenns blöd kommt, SDL, was eher kontraproduktiv für das Lernen von C++ ist) und vernachlässigt C++-Teile eher. Aber das ist nur meine Vermutung.

    Nein, es bindet sich nicht daran. Mit der SDL wird am Ende lediglich ein (Grafik) Spiel geschrieben. Ansonsten hat das Buch nicht wirklich viel mit Spielen zu tun, ausser, dass man halt anstatt eines Rechners ein kleines Konsolenspiel macht und dass man keine Äpfel und Birnen hat, sondern Raumschiffe. 😉

    Bestimmt nicht das beste Buch, um C++ zu lernen, allerdings gibt es trotzdem einen guten Einstieg.



  • konnte es icht lassen es doch zu versuchen...

    Also erst mal Texturmanager.hpp

    #ifndef TEXTUREMANAGER_HPP
        #define TEXTUREMANAGER_HPP
    
    #include "Singleton.hpp"
    #include <map>
    
    #include "Texture.hpp"
    
    #define g_pTexturManager TextureManager::Get()
    class TextureManager : public TSingleton<TextureManager>
    {
        public:
        TextureManager();
        ~TextureManager();
    
        void AddTexture(const string& fileName);
        void RemoveTexture(const string& fileName);
        Texture& GetTexture(const string& fileName);
    
        private:
        map<string, Texture> MyTextures;
    };
    
    #endif //TEXTUREMANAGER_HPP
    

    Dann TexturManager.cpp

    #include "TextureManager.hpp"
    
    TextureManager::TextureManager()
    {
    }
    
    TextureManager::~TextureManager()
    {
        MyTextures.clear();
    }
    
    void TextureManager::AddTexture(const string& fileName)
    {
        bool Textureerstellen=true;
    
        if(MyTextures.empty()==false)
        {
            map<string,Texture>::iterator i;
            for(i=MyTextures.begin(); i!=MyTextures.end();i++)
            {
                if(i->first==fileName)
                {
                    cout<<"Textur existiert bereits"<<endl;
                    Textureerstellen=false;
                }
            }
        }
        if(Textureerstellen==true)
        {
            pair<string, Texture> T;
            Texture Tex(fileName);
            T=make_pair(fileName,Tex);
            cout<<"Textur wurde erstellt"<<endl;
        }
    }
    
    void TextureManager::RemoveTexture(const string& fileName)
    {
        if(MyTextures.empty()==false)
        {
            map<string,Texture>::iterator i;
    
            for(i=MyTextures.begin(); i!=MyTextures.end();i++)
            {
                if(i->first==fileName)
                {
                    MyTextures.erase(i);
                }
            }
        }
        else
        {
            cout<<"Kein Element in der Map"<<endl;
        }
    }
    
    Texture& TextureManager::GetTexture(const string& fileName)
    {
        map<string,Texture>::iterator i;
    
            for(i=MyTextures.begin(); i!=MyTextures.end();i++)
            {
                if(i->first==fileName)
                {
                    return i->second;
                }
                else
                {
                    cout<<"Textur wurde nicht gefunden"<<endl;
                }
            }
    }
    

    Ah und da noch ne Frage: Ist es besser den Iterator (und das pair?) in jeder Funktion neu zu erstellen oder in die Klasse als Membervariable zu schreiben?

    Dann Texture.hpp

    #ifndef TEXTURE_HPP
        #define TEXTURE_HPP
    
    #include <SDL/SDL.h>
    #include <SDL/SDL_opengl.h>
    #include <iostream>
    
    #include "TGA_Loader.hpp"
    
    using namespace std;
    
    class Texture
    {
        public:
    
        Texture();
        Texture(const string& FileName);
        //Texture(const Texture&);
        ~Texture();
        //void operator= (const Texture&);
    
        private:
        GLuint m_TextureID;
    };
    
    #endif //TEXTURE_HPP
    

    Die beiden Funktionen da als Kommentar(Kopierkonstruktor und Zuweisungsoperator) wusst ich nicht wie ich schreiben soll.

    und dann noch Textur.cpp

    #include "Texture.hpp"
    
    Texture::Texture()
    {
    }
    
    Texture::Texture(const string& FileName)
    {
        TGAImg Img;        // Image loader
    
       if(Img.Load(FileName)!=IMG_OK)
       {
           cout<<"Fehler beim laden der Textur: "<<FileName<<endl;
       }
    
       glGenTextures(1,&m_TextureID);
       glBindTexture(GL_TEXTURE_2D,m_TextureID);
    
       // Create the texture
        if(Img.GetBPP()==24)
         glTexImage2D(GL_TEXTURE_2D,0,3,Img.GetWidth(),Img.GetHeight(),0,GL_RGB,GL_UNSIGNED_BYTE,Img.GetImg());
        else if(Img.GetBPP()==32)
         glTexImage2D(GL_TEXTURE_2D,0,4,Img.GetWidth(),Img.GetHeight(),0,GL_RGBA,GL_UNSIGNED_BYTE,Img.GetImg());
        else
        {
            cout<<"Fehler: falsches Format von: "<<FileName<<endl;
        }
    
       glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
       glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
    }
    
    Texture::Texture(const Texture&)
    {
    }
    
    Texture::~Texture()
    {
         glDeleteTextures(GL_TEXTURE_2D,&m_TextureID);
    }
    

    So hoffe mal du hast das so in der Art gemeint.



  • Ja, du bist auf dem richtigen Weg. Willst du Texturen gleich über den Dateinamen identifizieren? Ich habe in meinem vorherigen Beispiel einen separaten ID-String verwendet, aber du kannst es auch so wie von dir gewünscht machen. Eventuell böte sich auch ein enum an, dann müssten aber die Anzahl Texturen schon zur Kompilierzeit feststehen.

    Du musst bei einer Map übrigens nicht immer durchiterieren, sonst kannst du gerade so gut einen anderen Container nehmen. 😉
    Schau dir am besten mal das an: http://www.cplusplus.com/reference/stl/map/.
    Besonders die Funktionen find() fürs Finden von Einträgen, insert() fürs Erstellen und erase() fürs Löschen. Du musst dabei nicht selber prüfen, ob Duplikate vorkommen, die std::map macht das für dich.

    Was den Kopierkonstruktor und Zuweisungsoperator angeht: Ich weiss nicht, ob sich das für dich lohnt, aber grundsätzlich wäre Reference Counting eine Möglichkeit. Das bedeutet, es wird gezählt, wie viele Instanzen sich eine Textur teilen. Am Anfang ist das nur eine, bei einer Kopie wird der Counter erhöht, im Destruktor reduziert. Die letzte Instanz (bei welcher der Count im Destruktor 0 wird) sorgt dann für die Freigabe. Aber eben, das nur mal so als Hinweis. Irgendwie sind das etwas viele neue Dinge aufs Mal, vielleicht lässt du das vorerst auch (d.h. du erstellst eine normale Kopie, einfach die defaultgenerierten Methoden zu verwenden ist keine Option).



  • ok also danke erst mal das du dir das alles durchgeschaut hast.

    Ja, du bist auf dem richtigen Weg. Willst du Texturen gleich über den Dateinamen identifizieren?

    Naja ich hätt mir halt gedacht ich mach das so, weil dann könnt ich dann wenn es die Textur nicht mehr gibt gleich mit dem Dateinamen die Textur erstellen. Also nur als Überlegeung. Und 2. wäre das nicht bisschen viel aufwand, wenn man dann vonmiraus mal so 200 Texturen hat?

    Eventuell böte sich auch ein enum an, dann müssten aber die Anzahl Texturen schon zur Kompilierzeit feststehen.

    Kann ich zwar jetzt nicht mit 100% sagen, würd aber eher mal sagen nein.

    Reference Counting eine Möglichkeit. Das bedeutet, es wird gezählt, wie viele Instanzen sich eine Textur teilen

    Das hört sich nicht schlecht an. Werd ich wahrscheinlich einbauen, dürfte ja eigentlich nicht so schwer sein einfach einen Zähler im Texturmanager der von jeder Textur alle Instanzen zählt.

    (d.h. du erstellst eine normale Kopie, einfach die defaultgenerierten Methoden zu verwenden ist keine Option).

    Versteh ich nicht ganz was du damit meinst



  • Also ich mache das genau auch so. Ich Identifiziere eine Textur anhand des Pfades. (Muss ja auch einmalig sein) und dann wird bei jedem, der genau auch diese Textur laden will, ob sie bereits vorhanden ist und ggf. wird ein Counter hochgezählt, respektive wieder runtergezählt, wenn das Objekt die Textur wieder freigibt.

    Somit wird eine Textur genau nur einmal geladen. Sofern man eine Textur noch irgendwie bearbeiten muss, kann man da ja schliesslich auch noch etwas mit COW machen.



  • stefan schrieb:

    Naja ich hätt mir halt gedacht ich mach das so, weil dann könnt ich dann wenn es die Textur nicht mehr gibt gleich mit dem Dateinamen die Textur erstellen. Also nur als Überlegeung. Und 2. wäre das nicht bisschen viel aufwand, wenn man dann vonmiraus mal so 200 Texturen hat?

    Stimmt, dein Vorgehen ist wie drakon (der übrigens auch so ein Fan von "naja" ist ;)) gesagt hat eine gute Idee, mach es also ruhig so.

    stefan schrieb:

    Das hört sich nicht schlecht an. Werd ich wahrscheinlich einbauen, dürfte ja eigentlich nicht so schwer sein einfach einen Zähler im Texturmanager der von jeder Textur alle Instanzen zählt.

    Nein, das müsstest du in der Texture -Klasse selbst einbauen, da das dort benötigt wird (für Konstruktoren, Zuweisungsoperator und Destruktor). Würdest du TextureManager dafür verwenden, hättest du wieder die unnötige Abhängigkeit.

    stefan schrieb:

    Versteh ich nicht ganz was du damit meinst

    Falls dir Reference Counting nicht passt, implementierst du normale Kopiersemantik (es wird eine neue Textursemantik erzeugt). Die vom Compiler automatisch generierten Kopierkonstruktor und Zuweisungsoperator sind insofern keine Option, als sie nur alle Member kopieren (und damit auf die gleiche Textur verweisen). Trotzdem versuchen dann beide Destruktoren, die Textur freizugeben, was kaum gut geht.



  • Naja hab jetzt das alles mal durchgelesen, aber ich komm nicht drauf.

    Und zwar hier wenn ich eine Textur erstellen will:

    void TextureManager::AddTexture(const string& fileName)
    {
        Texture Tex(fileName);
        cout<<"4."<<endl;
        m_T=make_pair(fileName,Tex);
        cout<<"5."<<endl;
        MyTextures.insert(m_T);
    
        cout<<"Textur wurde erstellt"<<endl;
    }
    
    Anders ist noch alles
    

    Es zeigt "4" an und danach stürzt das Program ab...
    Hab alles mögliche versucht, aber es sürzt immer ab oder es kommen haufen fehler.

    Anders sind die Funktionen so wie weiter oben noch, hab die zwar bisschen abgeändert. Also Iteratoren raus usw. So wie ich das halt am sinvollsten gefunden hab.

    Also hoffe mal ihr könnt mir noch mal helfen 🙂

    Und danke schon mal im vorraus.
    Und jetzt gut Nacht an alle.



  • Wäre noch gut, wenn wir etwas mehr über den Kontext von m_T erfahren könnten (Deklaration, andere wichtige Verwendung). Übrigens würde ich einen aussagekräftigeren Bezeichner wählen. 😉

    stefan schrieb:

    Hab alles mögliche versucht, aber es sürzt immer ab oder es kommen haufen fehler.

    Debuggt hast du wahrscheinlich noch nicht, oder? Wie stürzt das Programm ab? Normalerweise gelangt man zu der Stelle im Code, bei der das Programm abbricht. Wenn du die Variablenwerte mit dem Debugger laufend überprüfst, solltest du eigentlich schnell auf den Fehler stossen. Schau doch zum Beispiel mal, ob der Texture -Konstruktor richtig ausgeführt wird.



  • Hallo ____stefan____ 🙂

    zuersteinmal:

    #define g_pTexturManager TextureManager::Get()
    

    n e i n. da stellen sich alle c++ haare auf. Get musst nicht vermakrot werden.

    der code sieht an sich ok aus. wenn du aber "haufen fehler" bekommst, zeig sie
    uns. sogut raten können wir auch nicht. einfach 1zu1 ins forum mit dem fehler!

    ich könnte mir denken, dass es am ctor, copy-ctor oder sowas liegt. um genaueres
    zu sagen, brauchen wir den (aktuellen) code von

    Texture::Texture(const std::String &);
    Texture::Texture(const Texture &); // ich vermute den hauptfehler hier
    Texture::~Texture();

    so 🙂

    wenn ich auch mal das design bemäkeln darf, würde ich, wie bereits gesagt
    dass ganze mit refcounting machen. im idealfall nutzt du dafür zeiger:

    um dir einen hinweis zu geben, baue ich deinen texmanager + texture um 🙂

    class Texture
    {
    public:
        Texture(TextureManager *texmanager, unsigned ein_weiterer_parameter)
        {
            parent = texmanager;
            refcounter = 1;
    
            paramater = ein_weiterer_parameter; // stellvertretend für die variablen
    
            glGenTextures(); // das normale
        }
        ~Texture()
        {
            parent->RemoveTextureFromList(this); // entfernen vom manager
    
            // das übliche
    
            glDeleteTexture();
        }
        void AddRef()
        {
            ++refcounter;
        }
        void Release()
        {
            if (!--refcounter) // oje, wir ham die 0 erreicht
                parent->RemoveTexture(this); // und weg mit uns
        }
    private:
        Texture(const Texture &){} // wir werden nicht kopiert!
    
        TextureManager *parent;
        unsinged refcounter;
    
        unsigned alles_andere;
    };
    ///////////////////////////////////////
    ///////////////////////////////////////
    class TextureManager
    {
    public:
        typedef std::map<std::string, Texture *> texmap; // neu mit zeigern
        typedef texmap::iterator iter;
    
        friend class Texture;
    
        TextureManager()
        {
            // wir machen GARNICHTS
        }
        ~TextureManager()
        {
            for (iter = m.begin(); iter != m.end(); ++iter)
                delete iter->second;
    
            // ACHTUNG ACHTUNG
            // wenn eine textur auch ohne manager leben darf, muss hier ein
            // iter->second->Release(); hin
            // ansonsten bleibts hierbei
        }
        Texture *GetTexture(const std::string &filename)
        {
            iter it = m.find(filename);
            if (it != m.end())
            {
                it->second->AddRef(); // referenz-zählung
                return it->second;
            }
            else
            {
                Texture *tex = new Texture(filename, 42);
                m[filename] = tex;
                return tex;
            }
        }
        void RemoveTexture(Texture *tex)
        {
            for (iter it = m.begin(); it != m.end(); ++i)
            {
                if (it->second == tex)
                {
                    delete it->second; // entfernt sich automatisch aus der liste
                    return;
                }
            }
        }
    private: // PRIVAT
        void RemoveTextureFromList(Texture *tex)
        {
            for (iter it = m.begin(); it != m.end(); ++i)
            {
                if (it->second == tex)
                {
                    m.erase(it); // NUR entfernen
                    return;
                }
            }
        }
    
        texmap m;
    };
    
    // SO ab sofort fordern wir einen zeiger auf eine textur über GetTexture
    // an und Releasen ihn, wenn wir fertig sind. wenn wir ihn kopieren machen
    // wir vorher ein AddRef!
    
    class EinDings
    {
    public:
        EinDings(Texture *tex)
        {
            texture = tex;
            texture->AddRef();
        }
        EinDings(const EinDings &dings)
        {
            texture = dings.texture;
            texture->AddRef();
        }
        ~EinDings()
        {
            texture->Release();
        }
    private:
        Texture *texture;
    };
    
    // oder als funktion
    
    Texture *tex = texmanager->GetTexture("keksdose.bmp"); // refcount ist schon eins
    
    tex->Draw();
    
    // fertig
    tex->Release();
    

    wenn du das design zu 100% durchziehst, wirst du keine probleme haben,
    grade bei dem mehrfachverwenden ist das system sehr sinnvoll. wenn es dir jetzt
    noch abschmiert, dann nurnoch durch flüchtigkeitsfehler.

    ideal netürlcih, wenn du so alle ressourcen verwaltest.

    puh ganz schön viel code, aber es musste sein.

    dir weiterhin viel spaß ich geh ins bett 😃


Anmelden zum Antworten