char array vs. string



  • @Optimizer
    Wenn ich mir deine Klasse so anschaue, denke ich, du solltest besser bei Java bleiben.

    Allein die Operatorüberladung der Marke willkür treibt einem, der mal Scott Meyers gelesen hat Tränen in die Augen.

    Wenn du doch bei C++ bleiben möchtest, solltest du auf jeden Fall mal "Effective C++" zur Hand nehmen.



  • Und es ist jetz intuitiv charAt statt des in C++ üblichen operator[] zu verwenden? und es ist intuitiv die Methode equals zu verwenden, statt des in C++ üblichen operator ==?

    Was willst du mir damit sagen? Habe ich das falsche Wort verwendet? Was ich sagen wollte, hat Irgendwer in seinem Beitrag bereits angedeutet. const char* sind einfach nach wie vor der kleinste gemeinsame Nenner und ich bevorzuge aus diesem Grund in Schnittstellen von Komponenten die häufig (wieder)verwendet werden immer const char*. Aber vielleicht kannst du ja noch mal etwas ausführlicher deine Probleme mit meiner Antwort darlegen.

    Genau das meinte ich: In wie fern Portabler? Man braucht char* für Schnittstellen, was es aber doch nicht Portabler macht.



  • HumeSikkins schrieb:

    Optimizer schrieb:

    Aber nicht wahr, Hume, es ist ja so unglaublich falsch, eine anständige Klasse zu coden und damit das Problem ein für alle mal aus der Welt zu schaffen.

    Kannst du lesen oder bist du einfach nur daran interessiert rumzumaulen? Ich schrieb "generell" im Sinne von "im Allgemeinen".

    Super, und ich finde, generell sollte jeder mal ein String-Klasse schreiben. Genauso geile Begründung.
    So wie du es gesagt hast, ist es das schlimmste was man machen kann, wenn man einmal in seinem Leben so ne Klasse schreibt und die immer wieder verwenden kann.

    HumeSikkins schrieb:

    @Optimizer
    Wenn ich mir deine Klasse so anschaue, denke ich, du solltest besser bei Java bleiben.

    Allein die Operatorüberladung der Marke willkür treibt einem, der mal Scott Meyers gelesen hat Tränen in die Augen.

    Wenn du doch bei C++ bleiben möchtest, solltest du auf jeden Fall mal "Effective C++" zur Hand nehmen.

    Mach einen besseren Vorschlag. Ich habe weder gesagt, dass meine Klasse perfekt ist, noch dass ich übermäßig stolz auf sie bin. Ich habe sie geschrieben, um bequem Dateien in einer Schleife laden zu können (siehe weiter oben).
    Und wenn du was zu verbessern hast, dann lass es doch bitte hören.

    davie schrieb:

    und wie machst du

    string std_greet("hello"), place("world"), newline("\n");
    string greet = std_greet += " " + place += "!" + newline;
    

    Was beabsichtigst du genau? Vielleicht meinst du ja:

    String greet("hello"), place("world"), newLine("\n");
    String bla = greet + place + newLine;
    

    Helium schrieb:

    Und es ist jetz intuitiv charAt statt des in C++ üblichen operator[] zu verwenden? und es ist intuitiv die Methode equals zu verwenden, statt des in C++ üblichen operator ==?

    charAt() finde ich jetzt ziemlich intuitiv. Den Operator '==' wollte ich auch noch überladen, der soll dann die Methode equals() aufrufen. Dagegen ist ja nichts einzuwenden.



  • Ich persönlich sehe auch keinen Grund sich die Arbeit zu machen eine neue stringklasse zu schreiben.
    Ich wüsste auch nicht was ich davon habe ? Ne menge Zeitverlust. Und das in der ohnehin knapp bemessenen Zeit. Lieber erst anschauen wenn man es
    wirklich braucht.

    Wie bereits vorgestellt, überladen von operator<< als template hilft weiter. Ich selbst habe damit eine ini Klasse geschrieben um allerlei Datentypen wegschreiben zu können. Sollte man dann mal an einen Punkt kommen wo der Profiler aufheult vor schmerz kann man immernoch den operator für einen speziellen Typen spezialisieren und flott integrieren.

    Ich denke der Standard liefert massig Möglichkeiten. Ansonsten gibt es ja bereits erstellte Libs wie looki oder boost. Bevor ich also ewigkeiten in eine neue Klasse stecke bring ich lieber mal boost ans laufen.

    Zu der Sache:

    foo(char *);

    und string übergeben:

    Ich würde hier keinen Buffer kopieren. Meist kann man sich sicher sein das der String nur gelesen wird. Bevor ich also kopiere schliesse ich mich dem unsauberen design an
    und verspreche dem Compiler mit einem const_cast<char*>(string.c_str()); das nichts passiert. Nur in seltenen Fällen kopiere ich um.

    Ich denke jeder zieht erst mal den Standard vor . Erst wenn der Profiler den flaschenhals bei einer Standardmethode aufweisst macht man sich die mühe zu suchen.
    (Bei einer Ini Klasse ist z.B. i.d.r. nichts Zeitkritisches vorhanden...)

    Letzendlich darf man nicht vergessen das Entwicklungszeit mehr Kostet als Rechenzeit. Es bringt also nichts wenn man die schnellste Klasse der Welt hat, wenn keiner die Schnittstelle kennt. In der realität läuft vieles nicht ideal weil es einfach zu teuer wäre.



  • Ich stimme dir in den meisten Punkten zu. Ich habe die Klasse auch nicht zum Spaß geschrieben, sondern ich fand es einfach nur ZU arm, dass ich nicht mal nen einfachen Text mit variablen Werten darin erstellen konnte. Ich habe mich einfach maßlos über die Standard-stringklasse geärgert.
    Da meine Ausgabe nicht über cout funktioniert, sondern über Direct3D, war ich gezwungen, mir eine Möglichkeit zu suchen, ein passendes char-Array zusammenzubasteln.
    Ich habe mir dann eine ganze Weile mit stringstreams geholfen, aber irgendwann war mir das Ganze einfach zu hässlich.
    Zur Entwicklungszeit möchte ich sagen, dass das Ganze nicht länger als (insgesamt!) 5-6 Stunden gedauert hat und diese Zeit gewiss nicht verschwendet war.

    Mir wäre es auch lieber gewesen, std::string würde wenigstens so einfache Verknüpfungen (die trotz aller gegenteiligen Behauptungen kein hoch spezieller Wunsch meinerseits sind) unterstützen. Dann hätte ich mir den Aufwand auch sparen können, wie in anderen Programmiersprachen. Aber ja, es könnte ja sein, dass jemand bei <text> + <zahl> dann ne Verknüpfung <(zahl)text> + <zahl> = <zahl> haben möchte - lol.

    Das könnt ihr sehen wie ihr wollt, ich rate lediglich, std::string zu benutzen und wenn das nicht reicht, eine eigene Klasse zu schreiben (das war der Ausgangspunkt der Diskussion). Das ist ein einmaliger Aufwand.



  • Optimizer schrieb:

    Da meine Ausgabe nicht über cout funktioniert, sondern über Direct3D, war ich gezwungen, mir eine Möglichkeit zu suchen, ein passendes char-Array zusammenzubasteln.

    Alternativ könnte man auch einfach einen Wrapper um die dumme DirectX-Funktion basteln.



  • Optimizer schrieb:

    Mir wäre es auch lieber gewesen, std::string würde wenigstens so einfache Verknüpfungen (die trotz aller gegenteiligen Behauptungen kein hoch spezieller Wunsch meinerseits sind) unterstützen.

    nimm lexical_cast oder ähnliches - schreibs dir einfach selber:

    template<typename To, typename From>
    To convert(From const& from)
    {
      stringstream stream;
      stream<<from;
      To to;
      stream>>to;
      return to;
    }
    

    und schon kannst du
    string s = convert<string>(3);
    schreiben...

    sicher, es ist etwas langsamer, da der std Ctor aufgerufen werden muss - dafür hast du eine sau schneller string klasse (du hast scheinbar keine ahnung was da für jahrelange optimierungen drinnen stecken).

    Was stört dich an dem Convert?

    Das könnt ihr sehen wie ihr wollt, ich rate lediglich, std::string zu benutzen und wenn das nicht reicht, eine eigene Klasse zu schreiben (das war der Ausgangspunkt der Diskussion). Das ist ein einmaliger Aufwand.

    dann sollte man wohl eher zB flex_string von Alexandrescu verwenden 🙂
    Ne - also dieser einmalige Aufwand stimmt natürlich - aber warum die jahrelange Erfahrung der StdLibrary Implementierer (Implementatoren??) wegwerfen?

    Und durch eine (sorry, aber es stimmt) primitive Klasse ersetzen?
    Sicher, sie kann Zahlen verwalten, aber was ist mit neuen Zahlen? zB einen int128, int256,... und was ist mit krokodil und pinguin (um das Java Beispiel zu erweitern). Kannst ja einfach templates verwenden:

    template<typename Other>
    void string::append(Other const& other)
    {
      append(convert<string, Other>(other));
    }
    

    und schon hast du die selbe funktionalität 🙂

    somit könntest du wenigstens eine konvertierungen sinnvoll machen und nicht dauernd überladen...

    oder aber funktionen um dies für std::string zu ermöglichen.

    einziges Problem das ich sehe - sind so sachen wie GetWindowText, die einen buffer erwarten.

    Da schreibe ich aber immer einen wrapper - das ist natürlich etwas langsamer aber dafür kann man auch exception verwenden 🙂

    Für deinen Fall wäre vielleicht ein vector<char> besser?



  • // Operatoren '+=' zum Anhängen: 
        void operator+= (TCHAR *otherString); 
        void operator+= (const String &otherString); 
        void operator+= (__int32 int32Bit); 
        void operator+= (__int64 int64Bit); 
        void operator+= (bool value);
    

    Und was machst Du wenn der Anwender der Klasse einen std::string anfügen will ? Oder sogar eine eigene Klasse ?

    Ich verstehe halt nicht was dagegen spricht mit stringstream einen template operator<< und >> in einem namespace zu schreiben.

    Ansonsten sehe ich das so:

    Ich als einzelner Entwickler kann in 6h nicht das erschaffen was viele wesentlich fittere Leute über eine lange Zeit entwickeln.
    Es spricht ja generell nichts dagegen eine eigene Klasse zu schreiben. (Hab mir ja selbst die mühe gemacht eine Klasse zu schreiben die mit ini Dateien inkl. Kommentaren templates und verschatelten Inis klar kommt.... Inkl. Editor etc. Hab übrigens wesentlich länger als 6 Tage drann geknappert. Bin halt langsam 🤡.

    Generell sollte man verwenden was da ist und erst auf eigene Klassen umsteigen wenn es der Profiler zeigt oder die Anforderung an die Klasse wesentlich höher ist als die Klasse das leisten kann.

    Generell zu sagen: Bau eine eigene Klasse, erst danach verwende die Standardklassen finde ich schlichtweg falsch. Ich denke Du hättest einfacher und sicherer zu Deinem Ziel kommen können 🤡

    Aber irgendwie drehen wir uns im Kreis, die Aussagen sind immer wieder die gleichen 😕



  • DrGreenthumb schrieb:

    Sie taugen nicht als buffer. Wenn zum Beispiel die WinAPI einen string zu rückgeben will muss man zuerst einen char Array erstellen anschließend eine string Kopie anfertigen und dann Array wieder löschen. Wäre es nicht einfacher wenn man reserve aufrufen könnte und anschließend direkt in den Buffer schreiben könnte?

    Wie soll das gescheit funktionieren, dass eine Methode einen char* auf die internen Daten zurückgibt.
    So?

    str.erlaube_reinschreiben(100);
    schreib_rein(str.pointer());
    str.fertig_mit_schreiben();
    

    Dann kommt auf einmal irgend'ne Lib die einen, mit malloc() reservierten, Speicherbereich zurückgibt. Soll string dafür dann auch eine Methode haben, die danach wieder free() aufruft? Bashar hat das schon gut auf den Punkt gebracht.

    Es ist halt der C Weg und da C++ ja C compatible sein soll wäre das mit dem buffer schon schön. Aber notfals kann man das immer noch mit Vererbung hinzufügen.

    Das mit malloc und free wird auch nicht vorkommen weil die meisten Libs in eine Dll gepackt sind/werden können.

    Also meist löse ich das Problem so:

    class Str:public string{
        char*buf;
    public:
        Str():buf(0){}
        ~Str(){delete buf;}
    
        //inherit operator=
        template<class T>
        Str&operator=(T t){assign(t);return *this;}
    
        void set_size(const int i){delete buf;buf=new char[i+1];buf[0]=0;}
        void refresh(){assign(buf);delete buf;buf=0;}
    
        operator const char*(){return c_str();}
        operator char*(){return buf;}
    };
    

    Mir wäre es auch lieber gewesen, std::string würde wenigstens so einfache Verknüpfungen (die trotz aller gegenteiligen Behauptungen kein hoch spezieller Wunsch meinerseits sind) unterstützen.

    Bau std::string doch einfach aus. Wieso das ganze Rad neu erfinden wenn du nur einen Teil neu erfinden willst/musst?

    Alternativ könnte man auch einfach einen Wrapper um die dumme DirectX-Funktion basteln.

    Kommt darauf an wieviel dumme Funktionen es gibt. Sind es viele kann es schneller sein eine eigene string class zu schreiben oder die standard string class zu erweitern.



  • Für die kompatibilität zu C APIs gibt es aber vector!
    Den kann man als Buffer verwenden...



  • Irgendwer schrieb:

    Also meist löse ich das Problem so:
    ...

    Ja, dachte ich schon. Aber dann refresh() aufzurufen, statt delete tmp; ist irgendwie das selbe in grün.

    Kommt darauf an wieviel dumme Funktionen es gibt. Sind es viele kann es schneller sein eine eigene string class zu schreiben oder die standard string class zu erweitern.

    Weiß nicht, ob das aber auch besser ist. So einen Funktionsaufruf möchte ich sowieso nicht "frei" im Code haben. Lieber einen Wrapper rum, mit nur den wichtigen Parametern und gleich auch const string statt char*.



  • Bau std::string doch einfach aus. Wieso das ganze Rad neu erfinden wenn du nur einen Teil neu erfinden willst/musst?

    Klingt ja logisch. Aber es war jetzt eigentlich gar nicht so aufwändig, die Klasse zu schreiben. Und ich wollte mal was mit new und delete machen 😉 . Die meiste Zeit hab ich in der MSDN nach _tcslen ö.ä. gesucht, weil ich mit TCHAR arbeiten wollte. 🙄
    Der Rest, das ganze Überladen, sind fast alles 2-Zeiler.

    Mit Templates hab ich mich leider noch nicht beschäftigt, ich bezweifle nicht, dass da noch eine sehr viel elegantere Lösung möglich ist.
    Trotzdem verstehe ich nicht, was Hume mit "Operatorüberladung der Marke willkür" meint. Vielleicht könnte man das ja mal begründen, oder einen besseren Vorschlag machen, ich habe nie behauptet, dass meine Klasse die bestmögliche Lösung ist.



  • Die x= und die = Operatoren sollten zum Beispiel String & zurückgeben



  • Trotzdem verstehe ich nicht, was Hume mit "Operatorüberladung der Marke willkür" meint. Vielleicht könnte man das ja mal begründen, oder einen besseren Vorschlag machen, ich habe nie behauptet, dass meine Klasse die bestmögliche Lösung ist

    Ich habe einen sehr guten Vorschlag gemacht, wiederhole ihn aber gerne: Lies "Effective C++".

    Da du scheinbar überhaupt nicht verstehst oder berücksichtigst worum es in diesem Thread ursprünglich ging und da du aus diesem Grund offensichtlich nicht dazu in der Lage bist meine Aussagen einzuordnen - aus welchen Gründen kommt man sonst wohl zu merkwürdigen Einschätzungen wie:

    So wie du es gesagt hast, ist es das schlimmste was man machen kann, wenn man einmal in seinem Leben so ne Klasse schreibt und die immer wieder verwenden kann.

    - fehlt mir jede Lust hier noch weiter was zu schreiben.



  • Optimizer schrieb:

    Klingt ja logisch. Aber es war jetzt eigentlich gar nicht so aufwändig, die Klasse zu schreiben.

    Klingt vielleicht hart, aber die Klasse ist ja auch lahm...
    Lass mal n paar Peformance Tests gegen std::string laufen und du wirst schockiert sein.

    Ich hab da teilweise schon schöne Dinger gemacht, aber nicht mit STLPort mithalten können (die haben AFAIK die beste string Implementierung)

    Der Rest, das ganze Überladen, sind fast alles 2-Zeiler.

    Und was machst du bei einem __int256 Typ? die Klasse ändern?



  • Ich arbeite mich gerade in templates rein. Die PErformance ist bei dieser Klasse nicht so wichtig.


Anmelden zum Antworten