Warum gibt es in std :: string so viele String-Klassen?

56

Es scheint mir, dass viele größere C ++ - Bibliotheken am Ende ihren eigenen Zeichenfolgentyp erstellen. Im Client - Code haben Sie entweder die eine aus der Bibliothek verwenden ( QString, CString, fbstringusw., ich bin sicher , dass jemand ein paar nennen kann) oder hält zwischen dem Standardtyp umzuwandeln und die man die Bibliothek verwendet (die meisten Zeit beinhaltet mindestens eine Kopie).

Gibt es also ein bestimmtes Missfeature oder etwas Falsches std::string(so wie die auto_ptrSemantik schlecht war)? Hat sich das in C ++ 11 geändert?

Tamás Szelei
quelle
32
Es heißt "Not Invented Here-Syndrom".
Cat Plus Plus
10
@CatPlusPlus QString und CString waren beide vor std :: string.
Gort the Robot
8
@Cat Plus Plus: Dieses Syndrom scheint die Java-String-Klasse nicht zu beeinflussen.
Giorgio
20
@ Giorgio: Java-Programmierer sind zu beschäftigt, Problemumgehungen für Sprachmängel zu entwickeln, um sich Gedanken über Zeichenfolgenklassen zu machen (Android hat übrigens String neu erfunden).
Cat Plus Plus
9
@Giorgio: Das liegt wahrscheinlich daran, dass Javas hartcodierte syntaktische Unterstützung java.lang.String(mangelnde Überladung von Operatoren usw.) die Verwendung anderer Funktionen zu einem Problem machen würde.
Mechanische Schnecke

Antworten:

57

Die meisten dieser größeren C ++ - Bibliotheken wurden gestartet, bevor sie std::stringstandardisiert wurden. Andere enthalten zusätzliche Funktionen, die erst spät oder noch nicht standardisiert wurden, wie die Unterstützung von UTF-8 und die Konvertierung zwischen Codierungen.

Wenn diese Bibliotheken heute implementiert würden, würden sie wahrscheinlich Funktionen und Iteratoren schreiben, die auf std::stringInstanzen ausgeführt werden.

Ben Voigt
quelle
5
Die Unterstützung von UTF-8 ist seit C ++ 98 standardisiert. In einer so umständlichen und teilweise definierten Art und Weise, dass etwa niemand in der Lage zu sein scheint, es zu verwenden
AProgrammer
9
@AProgrammer: Ist chargarantiert groß genug, um jeden UTF-8-Codepunkt aufzunehmen. AFAIK, das ist die einzige "Unterstützung", die C ++ 98 bietet.
Ben Voigt
4
@AProgrammer: Diese Unterstützung ist wirklich ziemlich nutzlos.
DeadMG
4
@AProgrammer Dieses Gebietsschema ist möglicherweise ungültig, da wchar_tes nicht groß genug ist, um alle Unicode-Codepunkte darzustellen. Darüber hinaus wurde die gesamte Diskussion über UTF-16 als schädlich eingestuft, wobei das sehr zwingende Argument lautete, dass UTF-8 ausschließlich verwendet werden sollte
Konrad Rudolph,
6
@KonradRudolph, es ist nicht das Gebietsschemasystem, das dort defekt ist (die Definition von wchar_t ist "breit genug für jeden unterstützten Zeichensatz"); Systeme, die ein 16-Bit-Commit für wchar_t durchgeführt haben, haben gleichzeitig festgeschrieben, dass Unicode nicht unterstützt wird. Nun, der Schuldige ist Unicode, das zuerst garantiert, dass es niemals Codepunkte verwenden würde, die mehr als 16 Bit benötigen, dann Systeme, die sich auf 16 Bit verpflichten, wchar_t, und dann Unicode-Umschaltung, um mehr als 16 Bit zu benötigen.
Programmierer
39

String ist C ++ peinlich.

In den ersten 15 Jahren stellen Sie überhaupt keine Zeichenfolgenklasse bereit, sodass jeder Compiler auf jeder Plattform und jeder Benutzer seine eigenen erstellen muss.

Dann machen Sie etwas, das verwirrt darüber ist, ob es sich um eine vollständige Zeichenfolgenmanipulations-API oder nur um einen STL-Zeichencontainer handelt, mit einigen Algorithmen, die die auf einem std :: Vector duplizieren oder sich unterscheiden.

Wenn eine offensichtliche Zeichenfolgeoperation wie replace () oder mid () eine solche Unordnung von Iteratoren enthält, dass Sie ein neues Schlüsselwort 'auto' eingeben müssen, damit die Anweisung auf einer einzigen Seite angezeigt wird und die meisten Benutzer die gesamte Sprache aufgeben .

Und dann haben Sie Unicode-Unterstützung und std :: wstring, das ist nur arghh .....

<rant off> danke - mir geht es jetzt viel besser.

Martin Beckett
quelle
12
@DeadMG - ja und es wurde 1998 standardisiert, 15 Jahre nachdem es erfunden wurde und 6 Jahre nachdem sogar MSFT es benutzte. Ja, Iteratoren sind eine nützliche Methode, um ein Array und eine Liste gleich aussehen zu lassen. Denken Sie, sie sind eine naheliegende Methode, um Zeichenfolgen zu manipulieren?
Martin Beckett
3
C with Classes wurde 1983 erfunden. Nicht C ++. Die einzigen Standardbibliotheken sind diejenigen, die von Standard bestimmt werden - was seltsamerweise nur vorkommen kann, wenn Sie über einen Standard verfügen. Das frühestmögliche Datum für eine Standardbibliothek ist also 1998. Iteratoren können als genau gleich Indexe angesehen werden, sind jedoch stark typisiert. Ich bin alle für die Tatsache, dass Iteratoren im Vergleich zu Bereichen saugen, aber das ist nicht wirklich spezifisch für std::string. Das Fehlen einer String-Klasse im Jahr 1983 rechtfertigt es nicht, jetzt mehr davon zu haben.
DeadMG
8
Ich dachte, Iostreams wären C ++ 'große Verlegenheit ...
Doug T.
18
@DeadMG Vor 1998 verwendeten die Leute für viele Jahre C ++. 1985 schrieb ich mein erstes Programm mit C ++ Zuvor haben wir Code geschrieben und mussten irgendwo eine Zeichenfolgenklasse abrufen. Sobald wir diese alten Codebasen hatten, konnten wir sie nicht mehr wegwerfen oder von Grund auf neu schreiben, als wir einen Standard erhielten. Was nun hätte passieren sollen, ist, dass es eine String-Klasse geben sollte, die mit cfront geliefert wurde.
Gort the Robot
8
@DeadMG - Wenn niemand eine Sprache verwendet hätte, bis sie ein ISO-Zertifikat hatte, dann würde niemals eine Sprache verwendet werden, da dies niemals zu ISO führen würde. Es gibt keinen ISO-Standard für x86-Assembler, aber ich bin froh, die Plattform zu verwenden
Martin Beckett
32

Eigentlich gibt es einige Probleme mit std::stringC ++ 11, und ja, es wird ein bisschen besser, aber lassen Sie uns nicht weiterkommen.

QStringund CStringsind Teil alter Bibliotheken, daher existierten sie vor der Standardisierung von C ++ (ähnlich der SGI STL). Es handelt sich also hatte eine Klasse zu erstellen.

fbstringsehr spezifische Leistungsbedenken ansprechen. Der Standard schreibt eine Schnittstelle vor, und die Komplexität der Algorithmen garantiert Mindestanforderungen. Es ist jedoch eine Frage der Implementierungsqualität, ob diese schnell sind oder nicht. fbstringhat spezifische Optimierungen (speicherbezogene oder eine schnellere findzum Beispiel).

Andere Bedenken, die hier nicht erwähnt wurden (en vrac):

  • In C ++ 03 muss der Speicher nicht zusammenhängend sein, was die Interoperabilität mit C möglicherweise erschwert. C ++ 11 behebt das.
  • std::string Codierung ist nicht bekannt und es gibt keinen speziellen Code für UTF-8. Es ist einfach, eine UTF-8-Zeichenfolge darin zu speichern und sie versehentlich zu beschädigen
  • std::stringDie Schnittstelle ist aufgebläht , viele Methoden könnten als freie Funktionen implementiert worden sein, und viele werden dupliziert, um sowohl einer indexbasierten als auch einer iteratorbasierten Schnittstelle zu entsprechen.
Matthieu M.
quelle
5
In Bezug auf Bedenken 1 - C ++ 03 21.3.6 / 1 wird garantiert, dass c_str()ein Zeiger auf zusammenhängenden Speicher zurückgegeben wird, was für eine gewisse C-Interoperabilität sorgt. Sie können die Daten, auf die verwiesen wird, jedoch nicht ändern. Typische Problemumgehungen umfassen die Verwendung von a vector<char>.
John Dibling
@JohnDibling: Ja, und es gibt eine weitere Einschränkung: Es könnte eine Kopie im neu zugewiesenen Speicher entstehen (der Standard sagt nicht, dass dies nicht der Fall sein soll). Natürlich verhindert C ++ 11 auch nicht das Kopieren, aber da Sie es einfach tun &s[0]können, spielt es keine Rolle mehr :)
Matthieu M.
1
@MatthieuM .: Der über erhaltene Zeiger &s[0]darf nicht auf einen NUL-terminierten String zeigen (es sei denn, er c_str()wurde seit der letzten Änderung aufgerufen).
Ben Voigt
2
@Matthieu: Ein anderer Puffer ist nicht erlaubt. c_str()Msgstr " Rückgabe: Ein psolcher Zeiger p + i == &operator[](i)für jeden iEingang [0,size()]".
Ben Voigt
3
Bemerkenswert ist auch, dass niemand mehr MFC verwendet, weshalb es schwierig ist zu argumentieren, dass CString eine Zeichenfolgenklasse in modernem C ++ ist.
DeadMG
7

Abgesehen von den hier genannten Gründen gibt es noch eine andere - die binäre Kompatibilität . Die Autoren der Bibliotheken haben keine Kontrolle darüber, welche std::stringImplementierung Sie verwenden und ob sie das gleiche Speicherlayout wie ihre haben.

std::stringIst eine Vorlage, so wird ihre Implementierung von Ihren lokalen STL-Headern übernommen. Stellen Sie sich nun vor, Sie verwenden lokal eine leistungsoptimierte STL-Version, die vollständig mit dem Standard kompatibel ist. Beispielsweise haben Sie sich möglicherweise dafür entschieden, statischen Puffer in jeden einzufügen std::string, um die Anzahl der dynamischen Zuweisungen und Cache- Fehler zu verringern. Infolgedessen unterscheidet sich das Speicherlayout und / oder die Größe Ihrer Implementierung von denen der Bibliothek.

Wenn sich nur das Layout unterscheidet, schlagen einige std::stringMemberfunktionsaufrufe für Instanzen, die von der Bibliothek an den Client übergeben wurden, möglicherweise fehl, je nachdem, welche Member verschoben wurden.

Wenn auch die Größe unterschiedlich ist, std::stringscheinen alle Bibliothekstypen, die ein Mitglied haben, eine unterschiedliche Größe zu haben, wenn sie in der Bibliothek und im Client-Code markiert sind. Bei Datenmitgliedern, die dem Mitglied folgen, std::stringwerden die Offsets ebenfalls verschoben, und jeder vom Client aufgerufene Direktzugriffs- / Inline-Accessor gibt den Müll zurück, obwohl beim Debuggen der Bibliothek "OK" angezeigt wird.

Fazit: Wenn die Bibliothek und der Client-Code in verschiedenen std::stringVersionen kompiliert werden, sind die Verknüpfungen in Ordnung. Dies kann jedoch zu bösen, schwer verständlichen Fehlern führen. Wenn Sie Ihre std::stringImplementierung ändern , müssen alle Bibliotheken, die Mitglieder aus STL verfügbar machen, neu kompiliert werden, um dem std::stringLayout des Clients zu entsprechen . Und weil Programmierer möchten, dass ihre Bibliotheken robust sind, werden Sie sie selten std::stringirgendwo sichtbar sehen.

Um fair zu sein, gilt dies für alle STL-Typen. IIRC haben sie nicht standardisiertes Speicherlayout.

gwiazdorrr
quelle
2
Sie müssen ein * nix-Programmierer sein. Die C ++ - Binärkompatibilität ist nicht auf allen Plattformen gleich, und speziell unter Windows sind NO-Klassen, die Datenelemente enthalten, zwischen Compilern übertragbar.
Ben Voigt
(Ich meine, außer POD-Typen, und selbst dann sind explizite Verpackungsanforderungen erforderlich)
Ben Voigt
1
Vielen Dank für die Eingabe, obwohl ich nicht andere Compiler spreche, spreche ich andere STL.
Gwiazdorrr
1
+1: ABI ist ein großer Grund, eine eigene Version einer vom Compiler bereitgestellten Klasse zu erstellen. Ich wünschte, dies wäre die akzeptierte Antwort.
Thomas Eding
6

Es gibt viele Antworten auf die Frage, aber hier sind einige:

  1. Erbe. Viele String-Bibliotheken und -Klassen wurden VOR der Existenz von std :: string geschrieben.

  2. Zur Kompatibilität mit Code in C. Die Bibliothek std :: string ist C ++, da es andere String-Bibliotheken gibt, die mit C und C ++ arbeiten.

  3. Um dynamische Zuordnungen zu vermeiden. Die Bibliothek std :: string verwendet eine dynamische Zuordnung und ist möglicherweise nicht für eingebettete Systeme, Interrupt- oder Echtzeit-Code oder für Funktionen auf niedriger Ebene geeignet.

  4. Vorlagen. Die Bibliothek std :: string basiert auf Vorlagen. Bis vor kurzem hatten einige C ++ - Compiler eine mangelhafte oder sogar fehlerhafte Vorlagenunterstützung. Leider arbeite ich in einer Branche, in der viele benutzerdefinierte Tools verwendet werden und eine unserer Toolchains von einem großen Unternehmen der Branche C ++ nicht "offiziell" unterstützt (wobei fehlerhafte Inhalte Vorlagen sind).

Es gibt wahrscheinlich noch viele weitere Gründe.

Adisak
quelle
2
"Ziemlich kürzlich" bedeutet "Es ist ein Jahrzehnt vergangen, seitdem selbst Visual Studio eine vernünftige Unterstützung für sie hatte"?
DeadMG
@DeadMG - Visual Studio ist nicht der einzige nicht kompatible Compiler der Welt. Ich arbeite in Videospielen und wir arbeiten häufig an benutzerdefinierten Compilern für unveröffentlichte Hardwareplattformen (geschieht alle paar Jahre in den Konsolenzyklen oder wenn neue Hardware erscheint). "Ziemlich kürzlich" bedeutet heute - Im Moment unterstützen bestimmte Compiler Vorlagen nicht gut. Ich kann nicht spezifisch sein, ohne NDAs zu verletzen, aber ich arbeite derzeit an einer Plattform mit benutzerdefinierten Toolchains, bei denen die C ++ - Unterstützung - insbesondere die Einhaltung von Vorlagen - als "experimentell" eingestuft wird.
Adisak
4

Es geht hauptsächlich um Unicode. Die Standardunterstützung für Unicode ist bestenfalls miserabel, und jeder hat seine eigenen Unicode-Anforderungen. Zum Beispiel unterstützt die ICU jede Unicode-Funktionalität, die Sie sich jemals wünschen könnten, hinter der ekelhaftesten automatisch aus Java generierten Oberfläche, die Sie sich vorstellen können eine gute Zeit.

Darüber hinaus benötigen viele Benutzer unterschiedliche Unicode-Unterstützungsebenen - nicht alle benötigen die APIs für das komplexe Textlayout und dergleichen. Es ist also leicht zu verstehen, warum es zahlreiche String-Klassen gibt - die Standard-Klasse ist ziemlich schlecht und jeder hat andere Bedürfnisse als die neuen. Niemand schafft es, eine einzige Klasse zu erstellen, die viele plattformübergreifende Unicode-Unterstützungen mit einer ansprechenden Oberfläche ausführt.

Meiner Meinung nach ist dies hauptsächlich die Schuld des C ++ - Komitees, Unicode 1998 oder 2003 nicht richtig unterstützt zu haben, vielleicht war es verständlich, aber nicht in C ++ 11. Hoffentlich werden sie es in C ++ 17 besser machen.

DeadMG
quelle
Hallo, C ++ 20 hier, raten Sie mal, was mit der Unicode-Unterstützung passiert ist.
Passant Bis zum
-4

Das liegt daran, dass jeder Programmierer etwas zu beweisen hat und das Bedürfnis verspürt, für seine eine, großartige Funktion eine eigene großartige, schnellere String-Klasse zu erstellen. Es ist normalerweise ein wenig überflüssig und führt meiner Erfahrung nach zu allen Arten von zusätzlichen String-Konvertierungen.

Chad Stewart
quelle
7
Wäre dies der Fall, würde ich eine ähnliche Anzahl von String-Implementierungen in Sprachen wie Java erwarten, in denen die ganze Zeit über eine gute Implementierung verfügbar war.
Bill K
@BillK Die Java-Zeichenfolge ist endgültig, daher müssen Sie neue Funktionen an anderer Stelle einfügen.
Und mein Punkt ist, dass ich in 20 Jahren noch nie jemanden gesehen habe, der eine benutzerdefinierte String-Impelementation geschrieben hat. Stellen Sie sich vor)
Bill K
2
@Bill: Das könnte mit einer anderen Kultur zu tun haben. C ++ spricht diejenigen an, die die Details auf niedriger Ebene verstehen möchten. Java zieht diejenigen an, die nur die Arbeit mit den Bausteinen anderer erledigen möchten. (Beachten Sie, dass dies keine Aussage über eine bestimmte Person ist, die sich für eine der beiden Sprachen entscheidet, sondern über die jeweiligen Designziele und -kulturen der Sprachen.)
Ben Voigt,