Eigenen Typ "String" in c++ deffinieren - wie?
-
bastl schrieb:
...
Das mit dem berechnen ist nicht mein Problem ....Das war aber bislang das Einzige, worauf Du abzieltest ... der einzige (vermeintliche) Nachteil von std::strings, den Du als Arugment brachtest.
bastl schrieb:
...daß length() ein Funktionsaufruf ist und nicht ein Zeiger auf diese Variable! - also einige Takte mehr benötigt....
Auch ein Indirektion (wie sie bei Deiner "Zeigervariante" nötig wäre) kostet Zeit - selbst das Auslesen einer Variable kostet Zeit.
bastl schrieb:
... - Das hat mich irgendwie gestört - ...
Nun gut - wer keine Arbeit hat, macht sich welche

Natürlich hindert Dch niemand, die Zahl der Funktionsaufrufe zu verringern - allerdings solltest Du bedenken, dass Compiler sowas heutzutage exzellent können (gerade bei simplen Gettern) - Mach doch einfach mal einen Vergkeichstest (im Releasemode compiliert).bastl schrieb:
...Wenn die Länge nicht gespeichert würde, müsste sie jedesmal neu berechnet werden! - würde keiner machen! ...
Wie ? Jetzt doch nicht mehr? Hast Du nicht oben erklärt, genau so und nur so würden std::strings funktionieren?
bastl schrieb:
...Jedoch ist es zwingend notwendig in C++ diese Variable getrennt vom Array zu halten, da die Aufgabe und Bedeutung der beiden sich total unterscheiden und somit auch deren Aufgaben in der Klasse!...
Japp - die Anzahl der Zeichen eines Strings ist eine separate Information und man tut deshalb gut daran, sie separat zu behandeln.
Was war jetzt Dein Problem dabei?bastl schrieb:
...Man benötigt halt immer eine Klasse, auch wenn man nur eine Funktion damit anstebt....
Wer strebt weswegen wofür "nur eine Funktion an"?
Und was ist falsch daran, eine Klasse zu verwenden?
Hast Du Berührungsängste mit objektorientierter Programmierung?bastl schrieb:
...
Simon2 schrieb:
Ich kenne das ja auch, dass man sich einer neuen Sprache erst einmal in den Denkmodellen der bisher bekannten nähert, aber irgendwann kommt der Punkt, an dem man "springen" muss; an dem man "Java" programmieren muss und nicht mehr "C++ in Java", "C in C++", "Cobol in Java" ... oder "Pascal in C++".
Gut erkannt, und immer wieder möchte man mit Hilfe einer anderen Programmiersprache etwas verdeutlichen oder erklären - man läuft immer auf!...
Dann lass es doch einfach: Ich habe den starken Eindruck, dass niemandem hier die Pascal-Parallele geholfen hat, zu verstehen, was Du sagen willst.
Warum auch? Hier ist- ein C++-Forum,
- in dem Leute, die C++ kennen
- sich über C++ unterhalten
Warum nicht in C++ sagen, was man zu sagen hat?
bastl schrieb:
...Bei mir ist das einzigste Problem, daß QStrings nicht mit std::string harmonieren ...
Ich kenne mich mit "QStrings" nun leider gar nicht aus. Aber da ich immer noch annehmen muss, dass Du mit std::string nicht allzu viel Erfahrung hast, könnte ich mir vorstellen, dass diese Analyse unzutreffend ist.
Selbst wenn Du jetzt einen eigenen Stringtypen entwirfst, wirst Du den mit QStrings "harmonisieren" müssen ... und ob das wirklich besser funktioniert als mit std:string?bastl schrieb:
...und ich sowiso eine spezial Suche und Vervollständigung im Umgang mit linuxdateien implementiren möchte. Gibt eine spezial Implementierung, ist aber kein Muss sonder eher aufregend und spannend und bringt hier und da noch ein paar Takte weniger - hab ja sonst nichts besseres zu tun!
Ich stimme Dir vollkommen zu: Man kann viel Aufregendes und Spannendes programmieren ... und nicht Alles muss sich wirtschaftlich rechnen.
Allerdings:
- "Linuxspezifisches" sehe ich im ganzen Szenario nicht.
- "Vorzeitige Optimierung" ist in 99% der Fälle vergebliche Liebesmüh: Man hat hinterher einen Haufen Fingerbrecherei gemacht für schlecht wartbaren Code und ein Programm, das langsamer läuft.
- die Möglichkeiten der StdLib (std::string aber auch viele Andere nützliche Dinge) sind sehr weitgehend ... damit kann man fast alle "spezial Sachen" machen.Nochmal mein Tipp: Versuche eine gute Implementierung auf Basis der StdLib hinzubekommen, baue das Ganze dann einmal ohne StdLib und vergleiche:
- Performance (wie gesagt: Releasemode compiliert)
- Codelänge
- Allgemeinverständlichkeit (kannst mal einem Freund den jeweiligen (unkommentierten) Code geben und raten lassen, was er macht)
- Wartbarkeit (für Erweiterungen, Fehlersuche, ...)
- Nettoaufwand bei Implementierung und Test.DAS wäre doch gleichzeitig spannend als auch lehrreich (egal, welche Variante dann "gewinnt").
Gruß,
Simon2.
-
bastl schrieb:
hab ja sonst nichts besseres zu tun!
Das Gefühl habe ich auch, wenn ich mir so ansehe, ab welchen Kleinigkeiten (die zum Teil noch falsch sind) du dich aufregst.
bastl schrieb:
Jedoch ist es zwingend notwendig in C++ diese Variable getrennt vom Array zu halten, da die Aufgabe und Bedeutung der beiden sich total unterscheiden und somit auch deren Aufgaben in der Klasse!
Du kannst auch gerne das erste Array-Element zum Speichern der Länge benutzen, wenn du so Freude daran hast. Die Trennung macht schon Sinn, und du hast bisher noch kein Argument dagegen gebracht (nein, weil es in Pascal so ist, ist kein Argument).
bastl schrieb:
Man benötigt halt immer eine Klasse, auch wenn man nur eine Funktion damit anstebt.
So ein Unsinn. Es gibt in C++ nicht umsonst freie Funktionen.
bastl schrieb:
Es geht [...] darum, daß length() ein Funktionsaufruf ist und nicht ein Zeiger auf diese Variable! - also einige Takte mehr benötigt. - Das hat mich irgendwie gestört
Wie gesagt macht das durch Compileroptimierungen keinen Unterschied (selbst wenn es das tun würde, solltest du dich zuerst um wichtigere Dinge kümmern.
bastl schrieb:
- ist aber trivial, gauso wie das Problem, das ich hier lösen wollte!
Hast du dein Problem jetzt gelöst? Falls nicht, würde es vielleicht helfen, es in aller Ruhe nochmals zu formulieren. Vielleicht mehr in die Richtung, was man erreichen möchte und nicht, welcher Teil von C++ einen aufgrund mangelnder Kenntnisse daran hindert.
-
Nexus schrieb:
Da diese Pascal-Strings dermassen wichtig sind und C++ ohne sie folglich abgrundtief schlecht sein muss, könntest du vielleicht mal erklären, wie diese funktionieren. Nicht jeder hat früher mal Pascal programmiert.
Klassische Pascal String verwenden ein fixed-size Array (typischerweise 256 Byte gross). Im ersten Byte steht die aktuelle Länge, danach kommt der Text. Nullterminiert sind sie dafür nicht.
In neueren Pascal-Dialekten werden sie logischerweise nichtmehr verwendet, da 255 als maximale String-Länge einfach nichtmehr ausreicht.
Und dann gibt es natürlich viele Abarten davon. z.B. Strings die die Länge in zwei oder mehr Byte speichern, die kein fixed-size Array verwenden sondern eins was immer nur so lange ist wie nötig, etc.
In Windows gibt's auch einen ähnlichen Typ, nämlich BSTR. Ein BSTR ist ein nullterminierter UTF-16 String. BSTR ist ein Typedef auf "wchar_t*", und dieser Zeiger zeigt auf das erste Zeichen des Strings. Das "minus erste" Zeichen gibt die Länge an.
----
Der Vorteil von solchen Strings ist, dass sie unabhängig von der ABI einer bestimmten Programmiersprache sind -- da direkt das Layout im Speicher definiert ist. Dadurch kann man unabhängig von der Sprache Strings herumreichen, hat aber trotzdem den Vorteil, dass man a) die Länge nicht zählen muss und b) Null-Zeichen mitten im String haben kann.
Der Nachteil ist natürlich dass man sich genau an dieses Layout halten muss, und man dadurch weniger flexibel ist was diverse Optimierungen angeht.----
Im Prinzip könnte man nach diesem Schema auch std::string implementieren. Macht bloss glaube ich keiner.
-
Der Aufbau einer eigenen Stringklasse ist zumindest sehr lehrreich.
Lange Zeit bevor STL wirklich Standard war habe ich allen solchen Paketen mißtraut und meine eigene Klasse gebaut, die ich auch debuggen konnte.
Als Basisklasse sollte man einen ganz simplen char* nehmen, und dann eine Klasse bauen, die dann eben auch herkömmliche C-Strings einfach behandeln kann.
Klar hätte die eigene Stringklasse den Längenwert bereits intus.
Dazu muß man aber auch sicherstellen, daß es einfach nicht gelingt, nachträglich ein 0-Zeichen in dem String unterzubringen.
Für eine solche Operation wäre eine von String abgeleitete Klasse sinnvoll.Für weiteres Training programmiere man sich dann mit Templates noch ein Array, damit man dynamisch eine Textdatei einlesen kann und sie direkt in einem Stringarray zur Verfügung steht - wie im guten alten GFA-Basic

Wenn ich heute irgendwas mit viel Stringgewurschtel (privat) schnell machen will, pack ich diese Sachen immer noch aus.
-
Bitsy schrieb:
Dazu muß man aber auch sicherstellen, daß es einfach nicht gelingt, nachträglich ein 0-Zeichen in dem String unterzubringen.
WARUM?
Für eine solche Operation wäre eine von String abgeleitete Klasse sinnvoll.
WARUM?
Ich sehe die Gefahr nicht. In einen std::string kann ich auch 0-Zeichen reinstopfen, wie ich mag und habe ich damit keinen Ärger.
-
hustbaer schrieb:
Klassische Pascal String verwenden ein fixed-size Array (typischerweise 256 Byte gross). Im ersten Byte steht die aktuelle Länge, danach kommt der Text. Nullterminiert sind sie dafür nicht.
Das erste Byte als Größenangabe, der Rest als Zeichenfolge, keine Nullterminierung. Soweit klar.
Aber fixed-fized Array klingt nach tierischer Speicherplatzverschwendung. Daran mag ich nicht glauben. Zumal es nicht notwendig wäre, weil Pascal (im Gegensatz zu Basic) schon zu Zeiten des 64-ers eine Freispeicherverwaltung hatte. Kann es sein, daß die 640k vom DOS, sagen wir mal 500k Vokabelprogramm frei, nur 1000 Vokabelsätze gepaßt haben oder nur 500 Records mit Name/Vorname/Straße/Ort.
-
volkard schrieb:
hustbaer schrieb:
Klassische Pascal String verwenden ein fixed-size Array (typischerweise 256 Byte gross). Im ersten Byte steht die aktuelle Länge, danach kommt der Text. Nullterminiert sind sie dafür nicht.
Das erste Byte als Größenangabe, der Rest als Zeichenfolge, keine Nullterminierung. Soweit klar.
Aber fixed-fized Array klingt nach tierischer Speicherplatzverschwendung. Daran mag ich nicht glauben. Zumal es nicht notwendig wäre, weil Pascal (im Gegensatz zu Basic) schon zu Zeiten des 64-ers eine Freispeicherverwaltung hatte.War aber so, gerade weil man dem Programmierer beim Arbeiten mit Strings manuelle Speicherverwaltung à la C ersparen wollte.
Modernere Implementationen von Pascal (Delphi) verwenden ähnlich wie BSTR zusätzliche vier Bytes vor den eigentlichen Stringdaten, wo die Länge gespeichert wird; der String wird vollständig auf dem Heap alloziert (mit Referenzzählung und COW-Semantik), und so sind String-Variablen nur sizeof(void*) groß. Der Nachteil ist, daß
Length(theString)öfter mal einen Cache-Miss verursacht - aber i.d.R. kann der Compiler redundante Aufrufe (z.B. in einer Schleifenbedingung) ohnehin wegoptimieren.Ein schöner Aspekt dieser Implementation ist, daß der Compiler Stringliteralen gleich die Länge und einen angpaßten Referenzzähler voranstellen kann, so daß bei
const cSomeLiteral = 'some literal'; var S: String; SL: Integer; begin S := cSomeLiteral;keine Kopie angelegt, sondern nur der Referenzzähler erhöht werden muß, und
SL := Length (cSomeLiteral);sich auf eine Zeigerdereferenzierung beschränken kann.
Zwecks Kompatibilität mit dem Windows-API und C++Builder sind die Strings natürlich dennoch zusätzlich nullterminiert.
-
audacia schrieb:
War aber so, gerade weil man dem Programmierer beim Arbeiten mit Strings manuelle Speicherverwaltung à la C ersparen wollte.
die operatoren für strings waren doch eingebaut, oder? also kein new, strcpy und strcat.
hast du irgend eine quelle für diene these?
-
volkard schrieb:
die operatoren für strings waren doch eingebaut, oder? also kein new, strcpy und strcat.
In Wirths Pascal war, soweit ich mich erinnere, gar nichts dergleichen eingebaut; es gab nicht einmal einen Stringtypen (http://www.moorecad.com/standardpascal/pascalfaq.html#Q.%20How%20do%20I%20perform%20string%20operations%20in%20standa).
volkard schrieb:
hast du irgend eine quelle für diene these?
Nicht zur Hand, nein. Aber es liegt eigentlich nahe: für jeden String eine Heap-Allokation wurde als zu teuer angesehen, und so war ein stackbasierter String mit Komfort-Erweiterungen gegenüber
array[0..x] of charein guter Kompromiß.In der Implementation von Turbo Pascal war es darüber hinaus möglich, die Maximallänge des Strings explizit anzugeben:
var S: String[20]; // 21 Bytes großÜbrigens kannst du ja einfach Turbo Pascal herunterladen und nachschauen.
-
ok. bin überzeugt.
wieder was dazugelernt.
-
Falls es dich noch interessiert, hier ein uszug aus der Delphi-Doku zu "ShortString", der aus Kompatibilität zu TP auch heute noch zur Verfügung steht.
Delphi Hilfe schrieb:
Kurze String-Typen
Ein ShortString hat eine Länge von 0 bis 255 Zeichen. Obwohl sich seine Länge dynamisch ändern kann, beträgt die statische Speicherplatzzuweisung immer 256 Bytes. Im ersten Byte wird die Länge des Strings gespeichert, die restlichen 255 Byte stehen für die Zeichen zur Verfügung. Wenn S eine ShortString-Variable ist, gibt Ord(S[0]) die Länge von S zurück (dasselbe Ergebnis erzielen Sie mit Length(S)). Durch Zuweisung eines Wertes an S[0] können Sie (wie durch einen Aufruf von SetLength) die Länge von S ändern. ShortString wird nur aus Gründen der Abwärtskompatibilität mitgeführt.Delphi unterstützt kurze String-Typen (Untertypen von ShortString), deren maximale Länge zwischen 0 und 255 Zeichen liegen kann. Diese Typen werden mit einer Zahl in eckigen Klammern dargestellt, die auf das reservierte Wort string folgt. Zum Beispiel:
var MyString: string[100];Hier wird die Variable MyString mit einer maximalen Länge von 100 Zeichen erstellt. Die folgenden Deklarationen sind mit der obigen Zeile identisch:
type CString = string[100]; var MyString: CString;Bei Variablen, die auf diese Weise deklariert werden, wird dem Typ nur so viel Speicherplatz zugewiesen, wie für die angegeben Länge plus ein Byte erforderlich ist. Im obigen Beispiel belegt MyString 101 Byte. Für eine Variable des vordefinierten Typs ShortString wären dagegen 256 Byte erforderlich.
Bei einer Wertzuweisung an eine kurze String-Variable wird der String abgeschnitten, wenn die maximale Länge für den Typ überschritten wird.
Die Standardfunktionen High und Low bearbeiten Variablen und Typbezeichner für kurze Strings. High liefert die maximale Länge des kurzen String-Typs, während Low Null zurückgibt.
-
Don06 schrieb:
Falls es dich noch interessiert, hier ein uszug aus der Delphi-Doku zu "ShortString", der aus Kompatibilität zu TP auch heute noch zur Verfügung steht.
danke. das hat die sache noch hübsch abgerundet.
-
volkard schrieb:
Bitsy schrieb:
Dazu muß man aber auch sicherstellen, daß es einfach nicht gelingt, nachträglich ein 0-Zeichen in dem String unterzubringen.
WARUM?
Für eine solche Operation wäre eine von String abgeleitete Klasse sinnvoll.
WARUM?
Ich sehe die Gefahr nicht. In einen std::string kann ich auch 0-Zeichen reinstopfen, wie ich mag und habe ich damit keinen Ärger.
Ganz einfach 'axiomatisch'. Wenn du irgendwann aus irgendwelchen Gründen den eigentlichen cString mal wieder rausholst, kann der Zirkus losgehen.
Wie ich geschrieben hatte, eine abgeleitete Klasse bei der das 0 erlaubt ist, z.B. mit Namen stringbuffer, sagt mir da rein gefühlsmäßig mehr zu.Ich glaube, ich hatte damals sogar Gründe dafür, frag nicht, ist so lange her.
-
Dravere schrieb:
Ehm, hä? Ich verstehe immer noch nicht, was gegen die Klasse
std::stringspricht
Im Gegenteil, es erscheint mir die bessere Lösung zu sein.std::stringführt schliesslich intern die Grösse des Strings mit.Zur Lösung von Nexus:
Das geht nur, so lange das Array vorhanden ist. Sobald du ein Zeiger hast, geht diese Lösung nicht mehr.Grüssli
so kannst du verstehen, das erwähnen lieber std::string zu bevorzugen ist ein netter hinweis, doch jeder hat vl ein vorhaben, std::string erst mal zu verzichten und eigene string zu bauen, um mehr kenntnis zu erwerben. diese vl nur zum Testzwecke.
-
JnZn558 schrieb:
so kannst du verstehen, das erwähnen lieber std::string zu bevorzugen ist ein netter hinweis, doch jeder hat vl ein vorhaben, std::string erst mal zu verzichten und eigene string zu bauen, um mehr kenntnis zu erwerben. diese vl nur zum Testzwecke.
Hättest du den Thread gelesen, wüsstest du, dass es um etwas völlig anderes geht.
-
Bitsy schrieb:
...Wenn du irgendwann aus irgendwelchen Gründen den eigentlichen cString mal wieder rausholst, kann der Zirkus losgehen....
Zum einen gibt's keinen "eigentlichen cString da drin" - es ist vollkommen egal, wie std::string seine Daten intern organisiert.
Zum Anderen: Wieso sollte das mit einem "Pascalstring" anders sein, wenn man "den eigentlichen cString wieder rausholt" ?
Du erzählst hier von einer grundlegenden Schwäche von CStrings ... egal, ob Du sie aus irgendeinem Datentyp konvertierst und wenn, aus welchem.Gruß,
Simon2.
-
...aus einem selbstkonstruierten. Über den STL-string selbst habe ich gar kein Wort verloren.
-
Bitsy schrieb:
...aus einem selbstkonstruierten....
Auch wenn der CString aus einem von Dir selbst konstruierten Stringobjekt konstruiert wurde, hat er keine Möglichkeit, mehrere '\0'-en zu enthalten.
... oder er ist kein CString (oder exakter gesprochen: "NTCS" = "Null Terminated Character String").Die Quelle ist egal: JEDER CString hat diese Schwäche.
Gruß,
Simon2.
-
Was aber nicht allzu dramatisch sein sollte. Oder wie oft benutzt ihr
'\0'als Zeichen imstd::string?
-
Nexus schrieb:
Was aber nicht allzu dramatisch sein sollte. Oder wie oft benutzt ihr
'\0'als Zeichen imstd::string?Sehe ich ja auch so ... aber es ist als einziges (vermeintliches) Argument gegen std::string stehengeblieben und das ist auch noch falsch.

Gruß,
Simon2.