Was taugt std::string wirklich?
-
... schrieb:
Ich hab schon oft gelesen und gehört, dass std::string nicht wirklich gut sein soll.
das ist der fall. std::string ist nicht perfekt. und man soll std::string auch nur nehmen, wenn es deutliche vorteile vor char[] hat. also zu 99% ist std::string zu nehmen (kein witz!).
Da ich aber noch wenig Erfahrung habe und das nicht beurteilen kann, möchte ich mal eure Meinungen zu der Klasse hören.
std::string ist nur zu überbieten, wenn du sauviel erfahrung hast. und selbst dann nicht als allgemeine lösung, sondern immer nur in spezialfällen. es gibt halt nur *ein* std::stirng. man kann sich fein klassen bauen, die schneller concattenieren (vor allem mit expression templates). man kann sich feinklassen bauen, die für zumeinst sehr kurze strings besser sind (union, und daten in den speicher schreiben, wo sonst zeiger sind). man kann sich leicht klassen bauen, die sehr schnell vergleichen, wenn immer wieder die gleichen strings kommen (atomtabelle). ok, es ist nicht gerade leicht. und std::string schlägt man in den seltensten fällen um mehr als 50%.
Besonders interessant fänd ich, wenn ihr noch sagen könntet, was an der string Klasse gut oder nicht so gut ist.
sie funktioniert einfach. ohne fehler.
ich erinnere nur mal an das einlesen von zeilen aus einer datei. string wächst einfach so lange, bis die zeile reinpaßt. kein ärger mit overflows.BTW: Gibt es auch Anwendungsgebiete wo man mit den rohen char* arbeitet?
das betriebssystem nimmt als dateinamen rohe char*. ich wäre ungeschickt, wenn ich konstante dateinamen erst nach string konvertieren würde und dann doch .c_str() aufrufen würde.
als allgemeine regel würde ich sagen: nimm char*, wenn es geht. (also 1% oder so). nimm std::string sonst. bau die eine noch bessere klasse (also für dein konkretes programm bessere klasse), wenn du etwas besser machen kannst, als es std::string macht (wenn ich das recht einschätze, machen das nur leute wie ich und MrN, aber gurus wie marc++us und hume und shade machen das gar nicht). vielleicht solltest du gar nicht drüber nachdenken, was anderes als std::string zu nehmen.
-
es gab da auch mal die geschichte, dass std::string probleme macht wenns in einer klasse als membervariable verwendet wird die aus einer dll exportiert wird
wobei das erzeugen und löschen der klasseninstanzen ausserhalb der dll stattfindet
womit hängt das eigentlich zusammen?
@topic ich benutz std::string garnich... liegt aber daran dass viele embedded systeme keine stl ham. aber ich behaupt auch ned dass meine eigene stringklasse schneller is
-
... schrieb:
Ich hab schon oft gelesen und gehört, dass std::string nicht wirklich gut sein soll.
Nunja, gut ist relativ. Für Otto-Normalverbraucher reicht std::string locker aus. Wer intensiver mit Strings arbeitet, wird sich aber mit Sicherheit schon mal eine handlichere oder funktionsreichere Klasse gewünscht haben.
Ein Problem bei std::string bzw. std::wstring ist zB, dass man diese Klassen nur begrenzt für Unicode nutzen kann. Das liegt einfach daran, dass die Elemente immer gleich gross sind. Bei Unicode, zB UTF-8, haben die Zeichen aber eine variable Länge, je nachdem, wie sie codiert sind. Oder was ist mit Operatoren? Darüber hatten wir schon eine Diskussion und sind letztendlich zu dem Ergebnis gekommen, dass diese nicht immer glücklich gewählt sind. ZBstd::string a = "Hallo"; std::string b = " Welt!"; std::string c = a + b;
Wir schreiben hier a + b, und aus dem Mathematikunterricht wissen wir, dass dies bedeutet, a und b zu addieren. Strings werden aber nicht addiert, höchstens aneinandergehängt oder konkateniert. + ist hier jedenfalls nicht die beste Form die gewollte Aktion auszudrücken. "aaa" + "bbb" kann ja auch bedeuten, als Ergebnis "ccc" zu erhalten.
std::string hat aber auch Vorteile. Wesentlich ist hier, dass zum einen das Handling gegenüber C-Strings und den str... Funktionen einfacher ist. Zum anderen muss ein std::string intern nicht als C-String implementiert sein. Und das hat deutliche Vortiele. ZB hat allein die Längenermittlung von C-Strings eine Komplexität von O(n). Bei einem std::string ist dies konstant und idR ein simples 'return bla'. Also praktisch zu vernachlässigen.Fazit:
Wer intensives String Handling betreibt und enorme Funktionalität benötigt, sollte sich nach Alternativen umschauen. Für alle anderen ist std::string das Mittel der Wahl in C++ und 'char*' praktisch immer vorzuziehen. Allerdings gibts auch hier Ausnahmen von der Regel. ZB reicht für Literale 'const char*' allemal aus. Oder so ist std::string ungeeignet für Parameter in DLL Funktionen.MBCS-CITP schrieb:
Der Unerschied ist auch vollkommen klar. In einem Falle greife ich direkt auf den Speicher zu, im anderen anderen Falle rufe zunaechst einen new-Operator auf
In deinem Beispiel ja, stimmt aber so nicht ganz. Ein std::string verfolgt die Speicherpolitik, die ihm mit dem Allokator mitgegeben wird. Theoretisch sollte es also auch möglich sein, für einen std::string Stack zu verwenden.
MBCS-CITP schrieb:
und dann eine ueberladenen Operator, genau genommen am Ende ein kaschierter Methodenaufruf ist. Das muss langsamer sein und Heap verschwenden - vom Stack mal nicht zu reden, denn alle Aufrufe dahinter muessen wieder vom Stack verwaltet werden.
Nein. Wie du sicher weisst, können Funktionen geinlined werden.
-
std::string sollte in jedem Fall in c++-Programmen verwendet werden. Wenn man es nicht verwendet, dann nur zugunsten anderer String-Klassen, die entweder schneller sind oder weil man irgendwelche Bibs verwendet, die ihre eigene String-Klasse verwenden (wär aber in vielen Fällen besser, diese Bib-spezifischen Klassen wegzukapseln und nur an der Schnittstelle zur Bib zu verwenden). Praktisch nie sollte man char* verwenden um nichtkonstante Strings(!) in C++ darzustellen. Also sobald man irgendwas mit dem String macht (vergleichen, sortieren, kopieren ...) -> kein char*!
std::string wird zwar tatsächlich oft kritisiert, aber die kritik geht nicht dahin, dass man sie nicht verwenden soll, sondern dass sie vom Design her nicht so gut ist, wie sie sein könnte. Meist werden zwei Punkte angesprochen:
- Unicode kann nicht unterstützt werden (hier schon angesprochen) (wobei ich - ohne mich jemals näher damit beschäftigt zu haben das nicht versteh. Wieso kann man das nicht wenigstens über ne Spezialisierung machen???)
- Weil die Klasse eine fette schnittstelle hat. Nach Meinung einiger tonangebenden Gurus, sollte eine Klasse nur die notwendigen Methoden bieten. Alles was darüber hinaus geht und nur aus konfort-Gründen angeboten wird, sollte über non-member-non-friend-Funktionen angeboten werden. (s. http://www.gotw.ca/gotw/084.htm)Zweiteres spricht aber nicht gegen eine Benutzung (man sollte eher daraus für das eigenen Klassendesign lernen), ersteres nur in einem Spezialfall (wenn man Unicode verwendet).
Aussagen, dass std::string inperformant ist, sind prinzipiell mit Vorsicht zu genießen weil:
- Jeder Hersteller kann das Ding anders programmieren -> Performance so pauschal nicht vergleichbar
- Wer kann schon auf die schnelle ne String-Klasse besser implementieren als die hochbezahlten Jungs von Dinkumware, roguewave oder (weniger hochbezahlte) Open-Source-Gurus?@MBCS-CITP
Fairerweise solltest Du wenigstensconst std::string szString ("ABCDEFGHILKLMNOP");
schreiben. Und Code-Optimierung anschalten. Könnte sein, dass es da schon anders aussieht.
es gab da auch mal die geschichte, dass std::string probleme macht wenns in einer klasse als membervariable verwendet wird die aus einer dll exportiert wird
wobei das erzeugen und löschen der klasseninstanzen ausserhalb der dll stattfindet
das liegt schlicht und einfach daran, dass der export von Klassen in einer DLL nicht standartisiert ist. Prinzipiell kann man über ne dll nur C-sachen exportieren, weil das der kleinste gemeinsame Nenner ist. Also Funktionen und POD-Structs, keine Objekte. Wenn man Klassen exportiert, ist man darauf angewießen, dass auf beiden Seiten derselbe Compiler mit derselben Version und denselben Optimierungseinstellungen verwendet wird. Es gibt jetzt Herstellerspezifische Erweiterungen (z.B. in den MFC), die definieren, wie man Klassen doch exportieren kann, das geht aber nur in bestimmten Grenzen.
-
In diesem speziellen Fall ist das Problem, dass dann die DLL und der Client der DLL verschiedene Heaps verwenden. Der string wird am Heap der DLL angelegt und soll dann am Heap des Client zerstört werden. Das kann nicht gehen. Bei VC++ kann man es aber ermöglichen, indem man sicherstellt, dass beide Parteien die dynamische C-Runtime verwenden (msvcrt.dll).
-
groovemaster schrieb:
In deinem Beispiel ja, stimmt aber so nicht ganz. Ein std::string verfolgt die Speicherpolitik, die ihm mit dem Allokator mitgegeben wird. Theoretisch sollte es also auch möglich sein, für einen std::string Stack zu verwenden.
mach mal vor.
mir will nicht in den kopf, wie ich aus einer funktion heraus, mäclich dem ctor von string dann noch speicher vom stack abzocke und der speicher überlebt das funktionsende.
-
std::string _ist_ es.
Bye, TGGC
-
kartoffelsack schrieb:
- Unicode kann nicht unterstützt werden (hier schon angesprochen) (wobei ich - ohne mich jemals näher damit beschäftigt zu haben das nicht versteh. Wieso kann man das nicht wenigstens über ne Spezialisierung machen???)
std::string basiert auf dem STL-Container std::basic_string.
std::string ist die Klasse für "char" Strings.
std::wstring ist die Klasse für "wchar_t" Strings.D.h. für Unicode nimmt man die std::wstring Klasse.
Da im aktuellen C++ Standard die STL genormt ist, müssen alle Implementationen der STL identisch sein (zumindest von der Schnittstelle her).
Die Verwendung von Unicode erfordert sowieso das Studium des Unicode 4.0 Standards. Sonst kann es leicht passieren, daß man etwas übersieht.
Von den Container-basierten und ziemlich kurz gehaltenen String-Klassen der STL sollte man sich nicht zu viel erwarten, da sie nur eine minimale Programmierschnittstelle haben.
Durch Verwendung von std::wstring kann man jedoch viel Zeit sparen beim Behandeln von Unicode Strings.
Es gibt noch die C Library Funktionen für Unicode, mit denen man u.U. Konvertierungen etc. erledigen kann.
Was die Codeerzeugung betrifft: Wie Du bereits gesagt hast, erfordert die Reduktion des Codes einen guten Optimizer.
-
Power Off schrieb:
Von den Container-basierten und ziemlich kurz gehaltenen String-Klassen der STL sollte man sich nicht zu viel erwarten, da sie nur eine minimale Programmierschnittstelle haben.
schau mal ins wörterbuch, was "minimal" heißt und nimm dann diese aussage zurück. die stl-container sind eierlegende wollmilchsäue mit viel zu breiten schnittstellen. oder kannste mir mal erzähln, wozu ne map iteratoren haben sollte? damit man um baum auch aufwärtszeiger hat und pro knoten 4 byte wegschmeißt? ich kann es jedenfalls nicht nachvollziehen und ich brauche auch nie iteratoren von maps.
-
und wie läuft man sonst alle elemente einer map durch?
-
Ich verwende ne map zB in meinen Funktionen zum laden und speichern von INI Dateien und da ist der map-Zugriff per Name im Programm extrem praktisch, zum speichern brauch ich jedoch iteratoren um alle Elemente durchzugehen und abzuspeichern.
-
Power Off schrieb:
kartoffelsack schrieb:
- Unicode kann nicht unterstützt werden (hier schon angesprochen) (wobei ich - ohne mich jemals näher damit beschäftigt zu haben das nicht versteh. Wieso kann man das nicht wenigstens über ne Spezialisierung machen???)
std::string basiert auf dem STL-Container std::basic_string.
std::string ist die Klasse für "char" Strings.
std::wstring ist die Klasse für "wchar_t" Strings.D.h. für Unicode nimmt man die std::wstring Klasse.
Und hat immer noch verloren. wchar_t hat keine feste Größe und keine feste Kodierung. wstring erkennt trotzdem nicht mehr-char-zeichen, wenn du den Indexoperator benutzt. wstring weiß gar nichts, es ist nur ein Buffer mit der Funktionalität, einen anderen Buffer daran zu ketten. Die Speicherverwaltung nimmt der std::string ab, sonst nichts.
Da im aktuellen C++ Standard die STL genormt ist, müssen alle Implementationen der STL identisch sein (zumindest von der Schnittstelle her).
Ja richtig, nur die Schnittstelle.
Die Verwendung von Unicode erfordert sowieso das Studium des Unicode 4.0 Standards. Sonst kann es leicht passieren, daß man etwas übersieht.
Was denn zum Beispiel? Da gibt's nichts zu übersehen, Unicode 4.0 ist eine Tabelle mit Zahlen und Zeichen. Was für den Programmierer wichtiger ist, sind die Transformationsformate.
Von den Container-basierten und ziemlich kurz gehaltenen String-Klassen der STL sollte man sich nicht zu viel erwarten, da sie nur eine minimale Programmierschnittstelle haben.
Minimal ist sie nicht, du hast sogar die Wahl zwischen size() und length().
Durch Verwendung von std::wstring kann man jedoch viel Zeit sparen beim Behandeln von Unicode Strings.
Nein. std::wstring ist komplett unbrauchbar und immer plattform- sowie Compiler-abhängig.
-
Hallo,
ich habe bisher immer char* für Strings benutzt.
Jetzt möche ich die string Objekte aus der STL benutzen.
So weit so gut, nur beim einlesen gibet ein Problem (siehe Quellcode).// I N C L U D E ********************** // ************************************ #include <string> #include <iostream> using namespace std; // M A I N **************************** // ************************************ int main (void) { // String erzeugen - leer string s; // String einlesen cin.get(s.c_str(), strlen(s.c_str())); // Hier gibt es das Problem mit dem ersten Parameter // String ausgeben cout << s << endl; return 0; }
das Problem: cin.get(); erwartet als ersten Parameter einen "normalen" char* aber s.c_str() gibt einen const char* zurück.
Wie kann ich jetzt die Daten in den String einlesen ?
__stdcall*
-
// I N C L U D E ********************** // ************************************ #include <string> #include <iostream> using namespace std; // M A I N **************************** // ************************************ int main (void) { // String erzeugen - leer string s; // String einlesen // cin.get(s.c_str(), strlen(s.c_str())); // Hier gibt es das Problem mit dem ersten Parameter getline(cin, s); // String ausgeben cout << s << endl; return 0; }
Nicht so kompliziert denken.
-
glaubst du wirklich, dass es Sinn macht std::string zu benutzen, wenn man es eh nur als char* benutzen will?
#include <iostream> #include <string> int main() { std::string str; std::getline(std::cin, str); std::cout << str << '\n'; }
-
string s; cin>>s;
oder
string s; getline(cin, s);
-
volkard schrieb:
mach mal vor.
mir will nicht in den kopf, wie ich aus einer funktion heraus, mäclich dem ctor von string dann noch speicher vom stack abzocke und der speicher überlebt das funktionsende.Stack war das falsche Wort, ich meinte vielmehr nicht-dynamischen Speicher. Also Speicher, mit auto oder static Lebensdauer. Den Aufbau eines Allokators kannst du im Standard nachlesen und selbst herausfinden, ob du damit etwas funktionelles hinbekommst. Mir ist das leider zu umständlich, deshalb hab ich irgendwann mal, als ich zu Lernzwecken eine eigene String Klasse geschrieben habe, beides von Haus aus ermöglicht. Die Anwendung sieht dann wie folgt aus:
string<char> foo; // Freispeicher string<char, 100> bar; // Stack oder global
-
1. Besorg dir ein Buch über die C++ Standardlib, denn Streams, Strings u.a. haben alle ein Konzept, und das scheinst du noch nicht zu kennen.
2. Beschäftige dich mit Operator-Überladung, dann kannst du zumindest aus den Schnittstellen sehen, wie man damit umgeht.
3. Nicht in C denken!
-
User--- schrieb:
Ich verwende ne map zB in meinen Funktionen zum laden und speichern von INI Dateien und da ist der map-Zugriff per Name im Programm extrem praktisch, zum speichern brauch ich jedoch iteratoren um alle Elemente durchzugehen und abzuspeichern.
wie wärs mit einer sehr schnellen map ohne iteratoren und einer ein wenig langsameren map mit iteratoren?
-
Optimizer schrieb:
wstring erkennt trotzdem nicht mehr-char-zeichen, wenn du den Indexoperator benutzt. wstring weiß gar nichts, es ist nur ein Buffer mit der Funktionalität, einen anderen Buffer daran zu ketten. Die Speicherverwaltung nimmt der std::string ab, sonst nichts.
Dafür sind die Character-Traits zuständig: wenn die STL-Implementation Deines Compilers mit Unicode nicht umgehen kann, dann weißt Du, was zu tun ist.
Die Character-Traits beschreiben u.a. Collation (also Sortierung), wie Zeichen übersprungen werden usw. Ein Blick in den Standard hilft.Optimizer schrieb:
Was denn zum Beispiel? Da gibt's nichts zu übersehen, Unicode 4.0 ist eine Tabelle mit Zahlen und Zeichen. Was für den Programmierer wichtiger ist, sind die Transformationsformate.
Noch so ein Irrtum. Im Unicode-Standard sind z.B. auch Spacing und Compositing von Schriftzeichen festgelegt.
Im Chinesischen gibt es z.B. zusammengesetzte Schriftzeichen, die aus mehreren zusammengesetzt sind. Es gibt also noch Steuercodes, die das Zusammensetzen von Zeichen steuern. Ein Unicode Code-Point muß nicht unbedingt ein Schriftzeichen sein.
Das gleiche gilt für Kana-Überschriften von Kanji im Japanischen. Da gibt es auch spezielle Shift- und Kompositing-Modi.
Außerdem gibt es jede Menge Arten von Spacing, wie z.B. Vertikal-Spacing, hoch und runter, usw.
Den Unicode Standard muß man benutzen, wenn man Unicode-fähige Programme schreiben will, ansonsten wird das Programm nicht mehrsprachfähig.
Das wirst Du dann sehen, wenn sich der erste Chinese beschwert, daß er in Deinem Programm nix eingeben kann, oder ein Araber meckert über das falsch gruppierte Arabisch.
Optimizer schrieb:
Nein. std::wstring ist komplett unbrauchbar und immer plattform- sowie Compiler-abhängig.
C++ generell ist plattform- und compilerabhängig. Falls Du das noch nicht gemerkt hast, wird's langsam Zeit dafür.
Die Mindestgröße von wchar_t ist 16 Bit. Das entspricht unter Windows genau einem Unicode-CodePoint. Windows verwendet UTF-16 zur Codierung von Unicode-Zeichen.
Unter UNIXen ist wchar_t meist 32 Bit, dies erlaubt die Verwendung von UTF-32.
Das spielt aber für Unicode keine Rolle, da CodePoints in Unicode immer mindestens 32-Bit-Breit sind.
D.h. auf Systemen mit UTF-16 Codierung (wie Windows) muß man halt erst nach UTF-32 wandeln.
Dafür und für viele andere Sachen ist der Unicode Standard gedacht.