Warum geht das nicht?



  • Hi,

    ich hab eine Klasse (CString), die ist von std::string abgeleitet. Jetzt will ich auch schön Zahlen initialisieren können:

    CString::CString(const char *pchString) :
    std::basic_string<char>(pchString)
    {}
    
    CString::CString(int nNumber)
    {
        char chBuffer[16];
        sprintf(chBuffer, "%i", nNumber);
        CString(&chBuffer);  // expliziter Konstruktoraufruf
    }
    

    C:\Dokumente und Einstellungen\Chris\Eigene Dateien\Programmieren\Projekte\AGE\Source\Engine\String.cpp(30) : error C2372: 'chBuffer' : Neudefinition; unterschiedliche Zeigertypen
    C:\Dokumente und Einstellungen\Chris\Eigene Dateien\Programmieren\Projekte\AGE\Source\Engine\String.cpp(28) : Siehe Deklaration von 'chBuffer'
    C:\Dokumente und Einstellungen\Chris\Eigene Dateien\Programmieren\Projekte\AGE\Source\Engine\String.cpp(30) : error C2530: 'chBuffer' : Verweise muessen initialisiert werden

    Gut, evtl. liegt es an der Elementinitialisierungsliste, aber wie krieg ich das sonst hin?

    ChrisM



  • CString(&chBuffer);
    

    chBuffer ist ein array von dem must du nichtmehr explizit die adresse erzeugen weil ein array schon so quasi ein pointer ist (jajaja ich weiss ist nicht ganz korrekt) lass einach mal das & weg dann sollts gehen...

    p.s. normalerweise macht man das eh nicht über den umweg von sprintf sondern verwendet strinstreams...



  • Jetzt krieg ich andere Fehlermeldungen 😃

    C:\Dokumente und Einstellungen\Chris\Eigene Dateien\Programmieren\Projekte\AGE\Source\Engine\String.cpp(30) : error C2040: 'chBuffer' : 'class AGE::CString' unterscheidet sich von 'char [16]' in bezug auf die Anzahl vorgenommener Dereferenzierungen
    C:\Dokumente und Einstellungen\Chris\Eigene Dateien\Programmieren\Projekte\AGE\Source\Engine\String.cpp(30) : error C2512: 'CString' : Kein geeigneter Standardkonstruktor verfuegbar

    Ich weiß, sprintf() ist schlechter Stil und ich kenn auch die anderen Möglichkeiten aus der FAQ hier, aber ich brauch einfach nur Speed und das ist sprintf() genau richtig. Außerdem gibts ja keine Integerzahl auf 4 Byte, die 16 Stellen lang ist, Bufferüberlauf ist also ausgeschlossen. 🙂

    ChrisM



  • Man leitet doch nicht von std::string ab 😡



  • CString(&chBuffer);

    das erstellt ein temporäres objekt vom type CString

    den konstruktor kannst du nur in der initialisierungsliste aufrufen...
    aber du suchst uU ein
    CString::CString(int i)
    : basic_string<char>(Int2Str(i))
    {
    }
    wobei Int2Str eine private static methode von CString ist (oder eine globale funktion)

    übrigens, CString ist als Name nicht gut gewählt, die MFC besitzt bereits ein CString.



  • das heisst nichts anderes als das cstring keinen konstruktor für const char* (oder char*) hat

    ich bin mir jetzt nicht sicher ob man das so machen kann:

    CString::CString(int nNumber)
    {
        char chBuffer[16];
        sprintf(chBuffer, "%i", nNumber);
        string(&chBuffer);  //geht das?
    }
    

    oder ansonsten könnte man einfach noch sonen konstruktor reinschreiben:

    CString::CString(const char* str) : string(str)
    { }
    

    ich nehme an es gibt da irgendwas besseres aber naja 🙂



  • Danke, Shade of Mines' Lösung geht! 🙂

    übrigens, CString ist als Name nicht gut gewählt, die MFC besitzt bereits ein CString.

    Mein CString ist auch in einem Namespace 🙂

    Man leitet doch nicht von std::string ab

    So und warum bitteschön net?

    ChrisM



  • Original erstellt von ChrisM:
    So und warum bitteschön net?

    es ist gefährlich von std::string abzuleiten, aber vertretbar.

    std::string hat keinen virtuellen Destruktor, dh dass der CString Destruktor nicht aufgerufen wird, wenn ein CString Objekt als Zeiger auf string deletet wird.

    wenn man das aber bedenkt (also CString nicht polymorph verwenden) dann spricht nix dagegen.

    Auch wenn CString in einem namespace liegt, ist der Name trotzdem ungünstig.
    denn wenn ich CString sehe (zB weil irgendwo anders using deinNS::CString; steht) dann denke ich an MFC und erwarte ganz anderes Verhalten von CString.



  • Mal ne Frage, was hindert mich daran, das Template zu verändern wie ich will?
    Ja, ich weiß, ich sollte an den Headern nix verändern, aber so ein kleiner Engriff kann doch net schaden, oder?

    ChrisM



  • 😮 😮 🙄



  • Original erstellt von ChrisM:
    Mal ne Frage, was hindert mich daran, das Template zu verändern wie ich will?
    Ja, ich weiß, ich sollte an den Headern nix verändern, aber so ein kleiner Engriff kann doch net schaden, oder?

    jo genau und wenn jemand anders mal dein programm kompilieren will muss er sich extra noch deine frisierte stdandardbibliothek besorgen. und da deine nicht header anders heissen muss er noch extra zum kompilieren des einen programms den inluce path änder.... ausserdem kann die stdlib kompilerspezifisches zeug enthalten blah blah blah...

    [ Dieser Beitrag wurde am 20.04.2003 um 14:41 Uhr von japro editiert. ]



  • OK, überzeugt, der Header bleibt wie er ist 😃

    ChrisM



  • So, die Probleme gehen schon los:
    Ich hab eine Funktion, die eine Exception wirft. Wenn ich als Parameter an diese Funktion nichts übergebe (als Parameter = void) klappt alles, übergebe ich aber ein const CString&, krieg ich nur "Debug Assertion failed! ... Expression: _CrtIsValidHeapPointer(pUserData)", wenn ich auf ignorieren drücke, dann noch eine andere Debug Assertion, dann wird die Exception behandelt und am Schluss noch eine Schutzverletzung. 😞

    Könnte das evtl. doch was mit dem Destruktor zu tun haben? (meine hat ja keine Member und folglich auch keinen Destruktor, ich verlass mich einfach auf den von std::string)

    ChrisM



  • minimalcode posten



  • So, wenn ich die Laufzeitbibliothek bei meiner DLL, die die Funktion hat, die die Exception wirft, und bei meiner EXE, die diese aufruft, auf Multithreaded DLL Debuggen stelle, gehts, aber ich will bei diesem Projekt keine geshared Laufzeitbibliothek!
    Kann das evtl. daran liegen, dass meine EXE den String erzeugt und die DLL ihn dann deleted (d.h. es versucht, weil er ja auf dem Heap der EXE liegt)? Aber eigentlich darf die DLL sowas doch auch bei einer Exception nicht versuchen, wenn nur eine konstante Referenz übergeben wird? Von Parametern aufrufen war bei Wurf einer Exception nirgends die Rede 😞

    ChrisM



  • Minimalcode, ok:

    // DLL - wenn ich den strName Parameter auskommentiere, gehts!
    class CScriptLanguageMgr
    {
    public:
        AGEAPI IScriptLanguage &GetScriptLanguage(const CString &strName) const;
    };
    
    void CScriptLanguageMgr::UnregisterScriptLanguage(const CString &strName)
    {
        /*// Remove specified instance of IScriptLanguage from the map
        ScriptLanguageMap::iterator i = m_ScriptLanguageMap.find(strName);
        if (i != m_ScriptLanguageMap.end())
            m_ScriptLanguageMap.erase(i);
        else*/
            //AGEERROR(CScriptLanguageNotFoundException, "Script language '" + strName + "' not found!");
            //throw CScriptLanguageNotFoundException("test", __FILE__, __LINE__);
        throw 1;
    }
    
    // EXE
    
    (pKernel->GetScriptLanguageMgr()).UnregisterScriptLanguage("a");
    

    ChrisM



  • So, sogar wenn ich statt CString std::string einsetze, tritt der Fehler auf!

    ChrisM



  • Ist das überhaupt gültig?

    (pKernel->GetScriptLanguageMgr()).



  • Ja, 100%. Und selbst wenn es nicht gültig wäre, würde es ja nichts machen, weil ich in der Funktion ja nicht auf this zugreife (siehe Quellcode oben). 🙂

    ChrisM



  • *push*

    ChrisM


Anmelden zum Antworten