C++ Bibliotheken im Umfang wie Java?


  • Administrator

    KuhTee schrieb:

    Also zB über den QString kann ich nicht meckern. Wesentlich angenehmer zu benutzen als std::string und hat natürlich eine ganze latte mehr an features.

    Eine ganze Latte mehr an Features, welche grundsätzlich gar nichts mit einem String zu tun haben. QString ist völlig überladen an Features, die Klasse ist nicht sauber in ihre Aufgaben aufgetrennt.

    Im übrigen wäre es mir neu, dass QString wirklich mehr Features unterstützt, als die C++ Standardbibliothek an Möglichkeiten anbietet. C++ verteilt eben diese Möglichkeiten nur auf die std::basic_string Klasse, die Algorithmen, die basic_istream und basic_ostream Klassen, usw. usf ...

    Grüssli



  • Dravere schrieb:

    KuhTee schrieb:

    Also zB über den QString kann ich nicht meckern. Wesentlich angenehmer zu benutzen als std::string und hat natürlich eine ganze latte mehr an features.

    Eine ganze Latte mehr an Features, welche grundsätzlich gar nichts mit einem String zu tun haben. QString ist völlig überladen an Features, die Klasse ist nicht sauber in ihre Aufgaben aufgetrennt.

    Im übrigen wäre es mir neu, dass QString wirklich mehr Features unterstützt, als die C++ Standardbibliothek an Möglichkeiten anbietet. C++ verteilt eben diese Möglichkeiten nur auf die std::basic_string Klasse, die Algorithmen, die basic_istream und basic_ostream Klassen, usw. usf ...

    Bei der komischen Philosophie hätten sie sich std::string gleich sparen können und std::vector<char> nehmen können. Diese "String ist nur ein Container und alle Funktionen sind wo anders"-Idee ist doch nur Chaos.



  • 9 schrieb:

    Bei der komischen Philosophie hätten sie sich std::string gleich sparen können und std::vector<char> nehmen können. Diese "String ist nur ein Container und alle Funktionen sind wo anders"-Idee ist doch nur Chaos.

    Also std::string kann schon ein bischen mehr als std::vector. Es gibt sogar Leute, die finden, dass er viel zu viel kann 😉

    Die "komische Philosophie" finde ich persönlich manchmal schwerer verständlich bzw. durchschaubar. Derart designte Libs mögen stärker von einer guten Dokumentation abhängen oder eine steilere Lernkurve haben. Trotzdem gibt es gute Argumente dafür, nicht alle nur denkbaren Funktionen direkt in eine Klasse zu packen. Ich würde das nicht von vornherein verteufeln.

    Stefan.



  • 9 schrieb:

    Bei der komischen Philosophie hätten sie sich std::string gleich sparen können und std::vector<char> nehmen können. Diese "String ist nur ein Container und alle Funktionen sind wo anders"-Idee ist doch nur Chaos.

    std::string hat noch sehr viel (zu viel) mehr Funktionalität als std::vector, z.B. die ganzen substring-Geschichten und so weiter.



  • 9 schrieb:

    Bei der komischen Philosophie hätten sie sich std::string gleich sparen können und std::vector<char> nehmen können. Diese "String ist nur ein Container und alle Funktionen sind wo anders"-Idee ist doch nur Chaos.

    Nein, vector<char> ist sicher nicht die richtige Lösung. Aber dass es in die Richtung geht, dass string nur ein Container ist, ist sicherlich nicht schlecht. Meiner Meinung nach sollte ein guter String ein auf verschiedene Zeichensätze optimierter Container sein. Ach was red ich da, einer? Mehrere! Für verschiedene Anforderungen verschiedene Strings! Der random access String, bei dem ich selbst mit utf8 noch super Zeichen rumschubsen kann gegen den cstring der für die C Anbindung den Speicher am Stück vorhält. Und da alle komplexere Funktionalität wie substring Bildung ausgelagert ist, kann jeder seine eigene Stringklasse einfach hinzufügen und von dem bereits fertigen Code profitieren.



  • Ich denke mal, es wäre noch interessant gewesen, std::string mehr als Adapter denn als eigener Container zu konzipieren. Als normalerweise unterliegenden Container könnte man std::vector nehmen, momentan ähnelt std::string dem sowieso ziemlich. Aber zum Beispiel wenn man eine grössere Datei in einen String einlesen will, würde sich die Datenstruktur von std::deque wohl besser eignen. So wäre man diesbezüglich etwas flexibler und nicht an ein dynamisches Array gebunden.



  • Nexus schrieb:

    Ich denke mal, es wäre noch interessant gewesen, std::string mehr als Adapter denn als eigener Container zu konzipieren. Als normalerweise unterliegenden Container könnte man std::vector nehmen, momentan ähnelt std::string dem sowieso ziemlich. Aber zum Beispiel wenn man eine grössere Datei in einen String einlesen will, würde sich die Datenstruktur von std::deque wohl besser eignen. So wäre man diesbezüglich etwas flexibler und nicht an ein dynamisches Array gebunden.

    Ohne zu wissen, wie std::deque implementiert ist, gehe ich mal davon aus, dass es sich eben nicht um ein dynamisches Array handelt 😉

    Wenn man aber std::string nicht als Array implementiert, handelt man sich mEn damit zu viele Nachteile ein. Z.B. müsste man für c_str() den String kopieren. Wohin? Was ist mit konkurrierenden Zugriffen? Auch find() und Konsorten wären wohl weniger effizient.

    Außerdem ist das Einlesen ganzer Dateien nicht unbedingt etwas, das man mit std::string (effizient) machen können sollte (oder gar muss). Das ist irgendwie kein typischer Anwendungsfall für die Klasse. Dann hätte ich schon lieber die Möglichkeit, std::string billig kopieren zu können (copy on write).

    Stefan.



  • Nexus schrieb:

    Ich denke mal, es wäre noch interessant gewesen, std::string mehr als Adapter denn als eigener Container zu konzipieren. Als normalerweise unterliegenden Container könnte man std::vector nehmen, momentan ähnelt std::string dem sowieso ziemlich. Aber zum Beispiel wenn man eine grössere Datei in einen String einlesen will, würde sich die Datenstruktur von std::deque wohl besser eignen. So wäre man diesbezüglich etwas flexibler und nicht an ein dynamisches Array gebunden.

    Klingt nach einem interessanten Ansatz, mit dem man mal etwas rumexperimentieren könnte *notier*.



  • DStefan schrieb:

    Ohne zu wissen, wie std::deque implementiert ist, gehe ich mal davon aus, dass es sich eben nicht um ein dynamisches Array handelt 😉

    Ich meinte damit auch eher std::vector . 😉
    std::deque ist normalerweise als Array von Arrays implementiert.

    DStefan schrieb:

    Wenn man aber std::string nicht als Array implementiert, handelt man sich mEn damit zu viele Nachteile ein. Z.B. müsste man für c_str() den String kopieren. Wohin? Was ist mit konkurrierenden Zugriffen? Auch find() und Konsorten wären wohl weniger effizient.

    Daran habe ich vorher auch gedacht, besonders an c_str() . Doch wann braucht man c_str() ? Hauptsächlich, um Kompatibilität zu C-Schnittstellen zu ermöglichen (nebenbei für den Dateinamen bei std::fstream ). Also lange nicht immer. Braucht man immer Random-Access für Strings? Wohl auch nicht. Die Default-Implementierung wäre dann wie bisher nutzbar, aber für spezielle Ansprüche eignet sich vielleicht eine andere Datenstruktur besser, und dann kann man auch deren Nachteile in Kauf nehmen.

    Dynamische Arrays sind einfach sehr schlecht, was Einfügungen/Löschungen in der Mitte oder am Anfang angeht. Die Reallokation bei grosser Anzahl Elemente ist ebenfalls nicht gerade schnell (auch wenn das oft vernachlässigt werden kann). Stell dir einen String vor, der als verkettete Liste programmiert ist. Du kannst nun wahnsinnig einfach und performant sämtliche Vorkommen eines Teilstrings durch einen anderen ersetzen. Wenn bei einem dynamischen Array nicht beide gleich gross sind, handelt man sich unter Umständen massive Performancenachteile ein.

    pumuckl schrieb:

    Klingt nach einem interessanten Ansatz, mit dem man mal etwas rumexperimentieren könnte *notier*.

    Könnte ich bei Gelegenheit eigentlich auch mal ausprobieren... Wenn wir ein paar Resultate haben, könnten wir darüber auch nochmals ausführlicher diskutieren, wäre sicher spannend. Ich muss allerdings schauen, momentan habe ich noch einige andere Dinge vor. 🙂



  • Nexus schrieb:

    Stell dir einen String vor, der als verkettete Liste programmiert ist. Du kannst nun wahnsinnig einfach und performant sämtliche Vorkommen eines Teilstrings durch einen anderen ersetzen.

    Dafür deutlich mehr (>2x) Speicherverbrauch. Denn zu jedem char muss man noch nen pointer auf den nächsten speichern. Und wenn man nicht massive Performance-Probleme bekommen will, wenn man von hinten durch den String iteriert, muss man noch nen zweiten Pointer auf das vorherige Element speichern. wohlgemerkt, pro char!



  • CHARming schrieb:

    Dafür deutlich mehr (>2x) Speicherverbrauch. Denn zu jedem char muss man noch nen pointer auf den nächsten speichern. Und wenn man nicht massive Performance-Probleme bekommen will, wenn man von hinten durch den String iteriert, muss man noch nen zweiten Pointer auf das vorherige Element speichern. wohlgemerkt, pro char!

    Ja, das ist eben der Preis. Für die meisten Fälle lohnt es sich wohl nicht und ein dynamisches Array eignet sich am besten. Das heisst ja nicht, dass es nicht auch manchmal anders sein kann. Zudem gibt es ja noch std::deque als Zwischenlösung.



  • DStefan schrieb:

    Z.B. müsste man für c_str() den String kopieren. Wohin?

    class KasFString
    {
            vector<char> stringdata;
        public:
            const char* c_str() const { return &stringdata[0]; }
    };
    

    Wo liegt das Problem dabei ?



  • pumuckl schrieb:

    Nexus schrieb:

    Ich denke mal, es wäre noch interessant gewesen, std::string mehr als Adapter denn als eigener Container zu konzipieren. Als normalerweise unterliegenden Container könnte man std::vector nehmen, momentan ähnelt std::string dem sowieso ziemlich. Aber zum Beispiel wenn man eine grössere Datei in einen String einlesen will, würde sich die Datenstruktur von std::deque wohl besser eignen. So wäre man diesbezüglich etwas flexibler und nicht an ein dynamisches Array gebunden.

    Klingt nach einem interessanten Ansatz, mit dem man mal etwas rumexperimentieren könnte *notier*.

    Ich experimentiere derzeit damit herum. Soll mal ein Webserver werden. Socket liest in eine Queue<char>. Strings wird es so gar nicht geben, nur Container (Ranges, die ihre Elemente besitzen) und Ranges(, die ihre Elemente nicht be4sitzen). Bis eine Anfrage abgearbeitet ist, wird einfach in der Queue der Speicher nicht gepoppt, womit alle "Strings" ohne Kopieren auskommen, bis am Ende zu send(), was dann kopieren darf, wenn der Speicher in zu kleinen Happen rumliegt und sendfile(), was kopieren muß, wenn der Dateiname zufällig auf zwei Seiten verteilt ist (beides dürfte eher selten vorkommen). Bin noch gar nicht weit, aber der Ansatz fühlt sich GUT an.



  • KasF schrieb:

    DStefan schrieb:

    Z.B. müsste man für c_str() den String kopieren. Wohin?

    class KasFString
    {
            vector<char> stringdata;
        public:
            const char* c_str() const { return &stringdata[0]; }
    };
    

    Wo liegt das Problem dabei ?

    Lies mal Nexus' Posting. Er wollte gerade nicht den String als dynamisches Array repräsentiert haben.

    Stefan.



  • DStefan schrieb:

    Lies mal Nexus' Posting. Er wollte gerade nicht den String als dynamisches Array repräsentiert haben.

    Ok, danke.



  • @DStefan
    ich denke unter "dynamischem array" verstehen die meisten ein auf dem heap angelegtes array (new[]) und kein std::vector / std::deque / ....

    Simon



  • theta schrieb:

    @DStefan
    ich denke unter "dynamischem array" verstehen die meisten ein auf dem heap angelegtes array (new[]) und kein std::vector / std::deque / ....

    Simon

    Aber genau das macht std::vector doch. Vielleicht sollte man "verwaltetes dynamisches Array" sagen?

    Stefan.



  • Damit keine Missverständnisse entstehen: Ich habe mich auf die internen Datenstrukturen der Container bezogen. Also

    • dynamisches Array bei std::vector
    • mehrere dynamische Arrays bei std::deque
    • doppelt verkettete Liste bei std::list

    Was die Strings betrifft, so könnte man auch abgesehen von der internen Datenstruktur gewisse Dinge ausprobieren. Wahrscheinlich gibt es einige Optimierungen, was das Kopierverhalten betrifft (ich weiss ja nicht, wie gut COW immer umgesetzt ist). Z.B. sowas wie shared_string . Oder ein String, der noch kompatibler zu C ist und sich zum Beispiel auch in den Speicher schreiben lässt. Man müsste dann halt eine Lösung finden, um die Invarianten sicherstellen (Position der Nullterminierung).

    Dazu habe ich eigentlich nichts Konkretes, das sollten nur mal ein paar spontane, in den Raum geworfene Ideen sein. Ich kann mir vorstellen, dass zumindest das Herumexperimentieren ab und zu recht interessant sein kann... 🙂



  • Nexus schrieb:

    Dazu habe ich eigentlich nichts Konkretes, das sollten nur mal ein paar spontane, in den Raum geworfene Ideen sein. Ich kann mir vorstellen, dass zumindest das Herumexperimentieren ab und zu recht interessant sein kann... 🙂

    Es wird sich verdammt viel ändern, schätze ich. Ein Iterator ist was, was sich wie ein Zeiger anfühlt. Ein String ist was, was sich wie ein container of char anfühlt. Und das ist erst der Anfang, in Wirklichkeit ist es viel einfacher, wenn man die Schwelle überspringt, aber viel komplizierter für uns. Zufällig kommt c++0x zeitgleich mit dem Vulkanausbruch, daß die stl weitgehend verstanden ist und sich überlegene Begriffe auftun(, die noch weitgehend unverstanden sind). Es wird ein ganz fetter Bums kommen. C++ wird keine einheitliche Gemeinde mehr sein (falls sie das jemals war). Es wird viele Neusachen-Ablehner geben, viel mehr als beim alten Standard oder boost, es wird viele Abspringer geben, die "es einfach nicht mehr einsehen".
    Wir werden in interessanten Zeiten leben.



  • volkard schrieb:

    Wir werden in interessanten Zeiten leben.

    Hinzu kommen noch interessante Vorschläge, wie von den Iteratoren abzukehren und sich auf Ranges zu besinnen. Auch dies würde C++ im Kern ein weiteres mal umkrempeln, wenn so die Monopole der funktionalen Sprachen gestürmt werden: Lazy Evaluation und unendliche Datenstrukturen. Ein Ausflug nach Haskell hat mir erst gezeigt, wie einfach man zum Beispiel das Auslesen aus einer Datei machen kann: Als Liste von Zeilen die über Lazy evaluation dynamisch beschafft werden, wenn sie gebraucht werden.

    Mit dem Neuen Standard ist C++ mächtig genug um das ganze Repertoire funktionaler Programmierung einfach und effizient abzubilden. Und ich denke, diese Chance sollte man nutzen.


Anmelden zum Antworten