Templateprobleme



  • Hi,

    ich bin mit shared_ptr<> doch net so zufrieden und hab mir jetzt meinen eigenen auf auto_ptr<> basierenden Smart Pointer (als Template) geschrieben.

    Das Problem ist nur, dass Funktion quasi erst compiliert werden, wenn ich sie auch verwende, d.h. ich sehe erst dann Fehler. Ich hab immer gedacht, wenn ich die Klasse instantiiere, wird sie komplett erstellt?

    Und: Wie findet ihr die Klasse? Ist alles (korrekt) drin, was ihr von einem Smart Pointer erwartet?

    template<class type>
    class TPointer
    {
    public:
        TPointer(type *pPointer = 0)
        {
            m_bOwns = (pPointer != 0);
            m_pPointer = pPointer;
        }
    
        TPointer(const TPointer<type>& Source)
        {
            m_bOwns = Source.bOwns;
            m_pPointer = Source.Release();
        }
    
        ~TPointer()
        {
            if (m_bOwns)
                delete m_pPointer;
        }
    
        TPointer<type>& operator=(const TPointer<type>& Source)
        {
            if (this != &Source)
            {
                if (m_pPointer != Source.pPointer)
                {
                    if (m_bOwns)
                        delete m_pPointer;
                    m_bOwns = Source.m_bOwns;
                }
                else if (Source.m_bOwns)
                {
                    m_bOwns = true;
                    Source.Release();
                }
                m_pPointer = Source.m_pPointer;
            }
    
            return *this;
        }
    
        type& operator*() const
        {
            return *m_pPointer;
        }
    
        type* operator->() const
        {
            return m_pPointer;
        }
    
        type* GetPointer() const
        {
            return m_pPointer;
        }
    
        type* Release() const
        {
            m_bOwns = false;
            return m_pPointer;
        }
    
    private:
        bool m_bOwns;
        type *m_pPointer;
    };
    

    ChrisM

    [ Dieser Beitrag wurde am 13.04.2003 um 22:11 Uhr von ChrisM editiert. ]



  • Original erstellt von ChrisM:
    **Das Problem ist nur, dass Funktion quasi erst compiliert werden, wenn ich sie auch verwende, d.h. ich sehe erst dann Fehler. Ich hab immer gedacht, wenn ich die Klasse instantiiere, wird sie komplett erstellt?
    **

    das ist ja das feine an templates. sie sind nicht da (im End-Code) wenn du sie nicht brauchst (im gegensatz zu "normalen" funktionen)
    wenn du deine templates explizit instanziieren willst, schreibst du einfach irgendwo im code

    template class foo<bar>
    

    und deine klasse foo wird mit bar instanziiert. und das genau an dieser stelle.
    ich hatte mit dem vc6 mal ein problem, dass ich aus dem weg geschafft habe, in dem ich meine template klasse vor der verwendung explizit instanziiert hab.

    deine klasse schaue ich mir jetzt auch noch an 🙂



  • template<class type>
    class TPointer
    {
    public:
        TPointer(type *pPointer = 0)
        {
            m_bOwns = (pPointer != 0);
            m_pPointer = pPointer;
        }
        /* mach draus nen ctor mit elementinitialisierungsliste:
        TPointer (type *pPointer = 0) : m_bOwns (pPointer != 0), m_pPointer(pPointer) {}
        */
        TPointer(const TPointer<type>& Source)
        {
            m_bOwns = Source.bOwns;
            m_pPointer = Source.Release();
        }
        /* dito */
    
        ~TPointer()
        {
            if (m_bOwns)
                delete m_pPointer;
        }
    
        TPointer<type>& operator=(const TPointer<type>& Source)
        {
            if (this != &Source)
            {
                if (m_pPointer != Source.pPointer)
                {
                    if (m_bOwns)
                        delete m_pPointer;
                    m_bOwns = Source.m_bOwns;
                }
                else if (Source.m_bOwns)
                {
                    m_bOwns = true;
                    Source.Release();
                }
                m_pPointer = Source.m_pPointer;
            }
    
            return *this;
        }
        //Ich nehme an, du weißt, wofür du deinen auto_zeiger verwenden willst
    
        type& operator*() const
        {
            return *m_pPointer;
        }
    
        type* operator->() const
        {
            return m_pPointer;
        }
    
        type* GetPointer() const
        {
            return m_pPointer;
        }
    
        type* Release() const
        {
            m_bOwns = false; //ooo const memberfunktion
            return m_pPointer;
        }
    
    private:
        bool m_bOwns;
        type *m_pPointer;
    };
    

    Wenn du deine klasse auch verwendest, wirst du sehen, ob sie passt.
    ich hab jetzt nur mal die syntax angeschaut. 🙂

    ob vielleicht ein

    operator type * () { m_Owner = false; return m_ptr; }
    

    gut wäre, falls der benutzer wieder kontrolle will?

    [ Dieser Beitrag wurde am 13.04.2003 um 22:23 Uhr von davie editiert. ]



  • Danke für die Infos und Tipps! 🙂

    Aber warum soll ich den ctor mit Elementinitialisierungsliste nehmen? Ich verwend die normalerweise nur für Memeber-Konstruktoren mit Parametern und const Membern.

    ChrisM



  • in dem fall ist es noch (relativ) egal, aber es ist besser, sich das anzugewöhnen.



  • Hmm... d.h. ich soll Members ab jetzt immer über die Initialisierungsliste initialisieren? Sieht das bei größeren Klassen dann nicht etwas komisch aus?

    ChrisM



  • Etwas_Groessere_Klasse::Etwas_Groessere_Klasse (int a, int b, int c, int d) :
    
    m_a (a),
    m_b (b),
    m_c (c),
    m_d (d),
    m_e (a+b),
    m_Instanz_von_Etwas_Kleinere_Klasse (a+b, b%d, m_e)
    
    {}
    

    sieht doch nett aus 😉
    also, wenn es sowas schon gibt, dann nutze es auch 🕶
    In der FAQ haben wir, glaub ich, auch einen beitrag, der sich damit beschäftigt.
    ansonsten benutz mal die suchfunktion. findest sicherlich viele gute argumente für solche listen 🙂

    [ Dieser Beitrag wurde am 13.04.2003 um 22:40 Uhr von davie editiert. ]



  • OK, danke, werd ich mir wohl angewöhnen 🙂

    Langsamer kanns net sein und das ist die Hauptsache 😃

    ChrisM



  • ist sogar oft schneller (ansonsten ctor + op=)



  • Ich glaube, mal gelesen zu haben (Effektiv C++ programmieren?), daß die Element-Initialisierliste NICHT in der im Konstruktor angegebenen Reihenfolge abgearbeitet wird, sondern stattdessen in der Reihenfolge, wie die Elemente in der Klassendefinition auftauchen! Frage: Stimmt das?!?!
    Wenn Du daher Deine Klasse so aufbaust

    class Etwas_Groessere_Klasse
    {
        Klein m_Klein;
        int m_e;
        //...
    };
    

    dann bekommst Du demnach ein ziemliches Problem bei folgender Elemente-Initialisierung:
    [cpp]
    Etwas_Groessere_Klasse::Etwas_Groessere_Klasse (int a, int b, int c, int d) :
    m_a(a),
    m_b(b),
    m_c(c),
    m_d(d),
    m_e(a + b),
    m_Klein(a + b, b % d, m_e) //m_e noch undefiniert!!??
    {}[/cpp]



  • daß die Element-Initialisierliste NICHT in der im Konstruktor angegebenen Reihenfolge abgearbeitet wird, sondern stattdessen in der Reihenfolge, wie die Elemente in der Klassendefinition auftauchen! Frage: Stimmt das?!?!

    Ja das stimmt. Die Elementinitialisierung in der Initialisierungsliste wird automatisch so angeordnet, dass sie der Deklarationsreihenfolge der Elemente entspricht. Wer also Abhängigkeiten zwischen einzelnen Elementen hat, sollte dies unbedingt berücksichtigen.



  • So hab grad ein Problem mit der Elementinitialisierungsliste, ich post das grad mal hier. 😃

    Also:

    class CString : public std::string
    {
    };
    
    class CPlugin
    {
    public:
        CPlugin(const CString &strFile);
        ~CPlugin(void);
    
    private:
        CString &m_strFile;
        HMODULE m_hModule;
    };
    
    CPlugin::CPlugin(const CString &strFile) :
    m_strFile(strFile)
    {
    }
    

    Gibt bei der Elementinitialisierungsliste von CPlugin::CPlugin(const CString&) folgende Fehler:

    Plugin.cpp
    c:\dokumente und einstellungen\chris\eigene dateien\programmieren\projekte\age\source\engine\plugin.cpp(24) : error C2440: 'initializing' : 'const class AGE::CString' kann nicht in 'class AGE::CString &' konvertiert werden
    Durch die Konvertierung gehen Qualifizierer verloren
    c:\dokumente und einstellungen\chris\eigene dateien\programmieren\projekte\age\source\engine\plugin.cpp(24) : error C2439: 'm_strFile' : Element konnte nicht initialisiert werden
    c:\dokumente und einstellungen\chris\eigene dateien\programmieren\projekte\age\include\engine\plugin.hpp(26) : Siehe Deklaration von 'm_strFile'

    ChrisM



  • Aua, kleiner Tippfehler, sorry das was schuld:

    private:
        CString &m_strFile;
    

    ChrisM



  • du willst ne referenz auf einen CString machen, der aber als "const" übergeben wird.
    entweder du benützt const_cast (...)
    oder
    du machst aus der Referenz eine Instanz:
    CString &m_strFile => CString m_strFile
    oder du nimmst das const im Konstruktor weg. Dann existiert die referenz als gültige aber nur solange, wie das Objekt auch existiert. folgendes bsp führt dann zu undefiniertem verhalten:

    CPlugin *foo () {
       CString x("Hello"); //Sprungmarke 1
       return new CPlugin (x); 
    }
    
    int main () {
       CPlugin *cpl = foo ();
       /*
         wenn du hier jetzt die referenz auf [Sprungmarke 1] benutzt
         bekommst du Probleme
       */
    }
    

Anmelden zum Antworten