Das C++-GUI-String-Dilemma



  • Hallo Leute,

    ich habe erst gerade einen Address-Manager in C++ und dem gtkmm Toolkit geschrieben. Meine logischen Klassen (Group und Contact) hatten für die Elemente wie Namen, Adresse usw. zuerst std::string benutzt, als es dann aber die GUI ging, traten (erwartete) Konvertierungsprobleme (z.B. beim serialisieren) zwischen Glib::ustring und std::string (Umlaute usw.) auf.

    Es hätte zwar die Möglichkeit gegeben mit Glib::locale_from_utf8() und Glib::locale_to_utf8() die ganze Geschichte zu konvertieren, so wären aber bei jedem Anzeigen eines Kontakts an die 40 Konvertierungen fällig gewesen, die beim serialisieren und deserialisieren noch nicht mitgerechnet -> keine gute Idee!

    Also weiter überlegt, eine weitere Möglichkeit wäre gewesen anstatt std::basic_string<char> ein std::basic_string<wchar_t> zu nehmen, aber da wären wohl ähnliche Probleme aufgetreten, bin also schon im Voraus von der Geschichte abgerückt.

    Am Ende hab ich's dann so gemacht, dass die logischen Klassen statt std::string nun Glib::ustring verwenden. Es geht zwar alles reibungslos, aber ich hätte es eben gerne so gehabt dass die logischen Klassen keine Abhängigkeiten entwickeln. Gut, die glib ist ziemlich verbreitet, aber trotzdem. Andererseits habe ich mir jetzt viel Konvertierungsarbeit geschenkt.

    Mich würde jetzt mal interessieren wie ihr mit diesem Problem umgeht, besonders mit anderen Toolkits, da ich bisher nur mit Gtk+/gtkmm gearbeitet habe.

    Bye

    GPC

    Btw. Bei sowas denke ich immer wehmütig an Java, da geht das irgendwie ein wenig einfacher 😕



  • Soweit ich das überblicke, lösen es fast alle Leute so wie Du... da heißen dann die Strings in der Anwendung eben alle CString (MFC) oder TString (VCL), oder manchmal auch BSTR und ähnliches (COM).

    Wie brennend das Thema ist sieht man daran, daß beim VC7 die MFC ja eigentlich bereits tot war, aber als zusätzliche Funktionen tatsächlich noch was für CString spendiert wurde, damit man CString leichter zu COM-Strings konvertieren kann und zurück.

    Vor allem wenn man kompatibel zu Unicode bleiben will/muß kommt man ohne die GUI-Strings nicht aus, wenn man Konvertierungen vermeiden will.

    Eine Königslösung dafür ist mir nicht bekannt.

    Und von Unicode wollen wir ja gar nicht reden... habe noch nie einen std::basic_string<wchar_t> im Einsatz gesehen. 🙂



  • Yo, das Problem liegt leider am C++-Standard, der keine Unicode-Strings hat. 😞 Deshalb haben die ganzen Tookits alternativen in peto.

    Dir bleibt nichts anderes übrig als die Toolkit-Strings auch in deiner Logic zu benutzen. Du könntest dir vielleicht auch eine Wrapper-Klasse bauen, das du nicht knallhart die Toolkit-Strings benutzt. Und bei einem eventuellen Wechsel nur die Wrapper-Implementierung austauschen mußt.

    @Marc++us! Habe letztens ein altest MFC-Projekt (VC6) in meinem VC++7.1 compiliert. Errors! Weil jetzt der CString in die ATL mit eingeflossen ist, ist jetzt ein Template. Ging aber einfach, deshalb kann ich da nichts genaueres zu sagen, außer es hat sich was getan in der MFC.



  • Marc++us schrieb:

    Wie brennend das Thema ist sieht man daran, daß beim VC7 die MFC ja eigentlich bereits tot war, aber als zusätzliche Funktionen tatsächlich noch was für CString spendiert wurde, damit man CString leichter zu COM-Strings konvertieren kann und zurück.

    Es lebe die Rückwärtskompatibilität 😉

    Artchi schrieb:

    Dir bleibt nichts anderes übrig als die Toolkit-Strings auch in deiner Logic zu benutzen. Du könntest dir vielleicht auch eine Wrapper-Klasse bauen, das du nicht knallhart die Toolkit-Strings benutzt. Und bei einem eventuellen Wechsel nur die Wrapper-Implementierung austauschen mußt.

    Hm, diese Idee gefällt mir eigentlich ganz gut. Mal schauen, da müsste man doch was in Richtung Templates machen können.

    Na ja, wie ist das eigentlich beim C++ Nachfolger, ich nehme mal an da ist Unicode im Standard drin, oder?



  • GPC schrieb:

    Na ja, wie ist das eigentlich beim C++ Nachfolger, ich nehme mal an da ist Unicode im Standard drin, oder?

    Welcher C++-Nachfolger?

    Grundsätzlich hat C++ für UTF16 Funktionen und Klassen im Standard drin, inklusive zahlreicher Funktionen dafür. Nur verwendet es keiner... hab noch nie ein Buchbeispiel zu C++ gesehen, daß wchar_t & Co verwendet.



  • ich hab schon ziemlich oft std::basic_string<TCHAR> gesehen, was ja im Unicode-Build zu std::basic_string<wchar_t> wird. das kann man doch wunderbar im zusammenhang mit der winapi benutzen.



  • Es wird doch gerade an einem neuen Standard gewerkelt, oder sehe ich das falsch?
    Verfolge das nämlich nicht direkt.

    Es ist auch nicht so einfach ein wchar_t zu verwenden, weil einige Funktionen der Standardbibliothek nicht so schön damit funktionieren, jedenfalls hab ich die Erfahrung gemacht. strlen z.B. kannst du jedenfalls schon mal vergessen.

    EDIT: Wieso verwendet wchar_t eigentlich keiner? Das Thema ist doch recht heikel!



  • GPC schrieb:

    Es ist auch nicht so einfach ein wchar_t zu verwenden, weil einige Funktionen der Standardbibliothek nicht so schön damit funktionieren, jedenfalls hab ich die Erfahrung gemacht. strlen z.B. kannst du jedenfalls schon mal vergessen.

    wcslen



  • Marc++us schrieb:

    Grundsätzlich hat C++ für UTF16 Funktionen und Klassen im Standard drin, inklusive zahlreicher Funktionen dafür. Nur verwendet es keiner... hab noch nie ein Buchbeispiel zu C++ gesehen, daß wchar_t & Co verwendet.

    Nein hat C++ nicht. Genau das ist ja das Problem. std::basic_string ist nicht für Multibyte Kodierungen geeignet und je nach Platform ist wstring (basic_string<wchar_t>) für UTF32 (also 32Bit ausgelegt) oder für UCS2 (16Bit). Wenn jemand in einen basic_string UTF16 reinpackt, ist das imho nicht mehr als ein Hack.

    Aber C++ und Unicode ist echt problematisch. Es gibt auch keine portable Thirdparty Library, die dafür ausgelegt ist.

    @GPC
    für wchar_t muss man eben die wchar_t und nicht die char-Funktionen benutzen. Entsprechend man: wcslen(3) usw.



  • Ah, ok. Dann werd ich mich mal über die oben genannten Funktionen schlau machen. Danke dir.



  • kingruedi schrieb:

    Wenn jemand in einen basic_string UTF16 reinpackt, ist das imho nicht mehr als ein Hack.

    Deckt aber 99% aller praxisrelevanten Fälle ab. Solange length() funktioniert... 🙂 Mal im Ernst, einen Hack sehe ich hier nicht. Das <T> steht doch dafür, daß ich hier einen beliebigen Typ reinpacken darf, solange er alle notwendigen Operatoren anbietet. wchar_t erfüllt das durchaus.

    Multibytekonvertierungen wird man außer beim File-IO doch wohl sowieso kaum verwenden, UTF16 deckt weitreichende Fälle ab. Und sobald man UTF8 codieren muß, kommt man ohne eine mehrere megabytegroße Tabelle ohnehin nicht mehr aus.

    Ich glaube der Hauptgrund für CString, TString und QString ist eher der, daß die Klasse basic_string<> von C++ keine vielseitigen Memberfunktionen hat. Und wenn man dann sowieso zu was anderem greifen muß, nimmt man dann gleich die Klasse der GUI-Lib, fertig.



  • Es muss eigentlich prinzipbedingt schon ein Hack sein. Ein String soll eine Zeichenkette darstellen. Sobald der String nicht mehr weiß, was ein Zeichen ist und was nicht, ist er nicht mehr mehr als ein Buffer. length() funktioniert halt eben nicht. Nach deiner Logik kann man auch ein Bitmap in einen basic_string<char> packen, da würde dann sogar length() wieder funktionieren. 😉



  • Außerdem, würdest du es riskieren, nur weil bei deinen westlichen Texten gerade alles passt, wstring zu verwenden? Ich nicht. Ich kenne kaum eine lib für C++ die das riskiert. Für den Firefox hat man gar 5 verschiedene String-Klassen geschrieben, IMHO std::string wirklich gar nicht benutzt. Schon lustig, man findet kaum eine Java-lib ohne java.lang.String aber man findet auch kaum eine C++ - lib mit std::string. 😉



  • Optimizer schrieb:

    Außerdem, würdest du es riskieren, nur weil bei deinen westlichen Texten gerade alles passt, wstring zu verwenden? Ich nicht. Ich kenne kaum eine lib für C++ die das riskiert. Für den Firefox hat man gar 5 verschiedene String-Klassen geschrieben, IMHO std::string wirklich gar nicht benutzt. Schon lustig, man findet kaum eine Java-lib ohne java.lang.String aber man findet auch kaum eine C++ - lib mit std::string. 😉

    Genau. In C++ Quelltexten findet man meistens const char* 🙄 🙄 🙄



  • Du könntest deine logische Schicht ja auch aus Templates aufbauen:

    template <typename StrType>
    class address
    {
     private:
     StrType m_first_name;
     StrType m_family_name;
     //...
    };
    

    Ist aber IMHO den Aufwand (Templates im Header --> werden mehrmals mitkompiliert) nicht wert.



  • Marc++us schrieb:

    kingruedi schrieb:

    Wenn jemand in einen basic_string UTF16 reinpackt, ist das imho nicht mehr als ein Hack.

    Deckt aber 99% aller praxisrelevanten Fälle ab. Solange length() funktioniert... 🙂 Mal im Ernst, einen Hack sehe ich hier nicht. Das <T> steht doch dafür, daß ich hier einen beliebigen Typ reinpacken darf, solange er alle notwendigen Operatoren anbietet. wchar_t erfüllt das durchaus.

    basic_string<T> erwartet aber 1 Zeichen = 1 T.

    Das wchar_t 2 Byte groß ist stammt noch aus der UCS2 Zeit. Unter Linux hat man zB wchar_t einfach auf 4 Byte umgestellt, entsprechend für UCS4.


Anmelden zum Antworten