char mit string vergleichen
-
Optimizer schrieb:
EDIT: Das Thema hat sich aber eh erledigt. string definiert einen
bool __cdecl operator==( const _Elem * _Left, const basic_string<_Elem, _Traits, _Alloc>& _Right)
Damit ist die Aussage, dass der Vergleich mit einer std::string-Konstante langsamer ist, sogar bewiesen falsch. :p
Wenn du gelesen hättest was ich geschrieben habe, hättest du dir das sparen können.
Es geht doch nicht darum, dass buffer konvertiert wird, sondern dass du für "f" ein string objekt konstruierst.
Und den Compiler zeig mir mal, der das schafft, das objekt, dass du explizit erstellt hast, wegzuoptimieren (es ist _möglich_ allerdings muss der Compiler da wirklich verdammt intelligent sein)
Wenn Programmierer verlangen, dass explizit generierte Objekte wegoptimiert werden soll, dann zweifle ich an den Programmieren.
Denn wenn ich
string("s")=="f"
schreibe - dann gehöre ich sowieso geschlagen...
-
Shade schrieb:
was spricht gegen ein
if(!strcmp(buffer, "F"))
?
oder besser
if(buffer[0]=='F')
?die beiden Ausdrücke [edit: die if(...)-Bedingungen] liefern aber unterschiedliche Ergebnisse!
Falls in buffer "Feldhase" steht, liefert die erste Variante false, die zweite true.
-
Der return-Wert von strcmp liefert nicht false oder true sondern bei zwei gleichen Strings null, bei ungleich -1 oder 1, je nachdem ob der String kleiner oder größer ist.
-
Shade Of Mine schrieb:
Wenn du gelesen hättest was ich geschrieben habe, hättest du dir das sparen können.
Stimmt, hab ich gar nicht gesehen, sorry.
Es geht doch nicht darum, dass buffer konvertiert wird, sondern dass du für "f" ein string objekt konstruierst.
Und worum geht es da genau, wenn "f" zur Compile-Zeit bekannt ist?
Und den Compiler zeig mir mal, der das schafft, das objekt, dass du explizit erstellt hast, wegzuoptimieren (es ist _möglich_ allerdings muss der Compiler da wirklich verdammt intelligent sein)
Ich denke, dass Compiler das auch schaffen können, wenn der Wert zur Compile-Zeit nicht bekannt ist. Wo ist denn das Problem? Der Compiler wird doch merken, dass er nen buffer kopiert, nur ausliest und gleich wieder löscht.
Denn wenn ich
string("s")=="f"
schreibe - dann gehöre ich sowieso geschlagen...Darum gehts ja nicht. Es geht um <unbekannter Wert im Buffer> == string("s").
-
Optimizer schrieb:
Ich denke, dass Compiler das auch schaffen können, wenn der Wert zur Compile-Zeit nicht bekannt ist. Wo ist denn das Problem? Der Compiler wird doch merken, dass er nen buffer kopiert, nur ausliest und gleich wieder löscht.
Das würde bedeuten, dass der Compiler die string klasse sehr gut kennst.
er muss dazu wissen, was strlen("f") liefert. dazu muss strlen() intrinsic sein. sollte "f" zur compiletime nicht feststehen kann er sowieso nix machen.ich gehe mal davon aus, dass string einfach implementiert ist - ohne besondere optimierung (zB nicht als char* sondern als eine art list oder so) - denn sonst wäre die optimierung gänzlich unmöglich.
betrachten wir den ctor:
string::string(char const* s) { length=strlen(s); if(length<STATIC_BUFFER_SIZE) { use_static_buffer=true; strcpy(static_buffer, s); } else { use_static_buffer=false; buffer=new char[length+1]; strcpy(buffer, s); } }
Das wegzuoptimieren ist schon ne ordentliche leistung.
er muss strlen(s) auswerten und erkennen, dass dann immer der eine if zweig ausgeführt wird.dann der op==
bool operator==(char const* s1, string const& s2) { return !strcmp(s1, s2.c_str()); }
dazu müssen wir c_str kennen:
char const* c_str() const { if(use_static_buffer) return static_buffer; else return buffer; }
Jetzt muss der compiler wissen, dass wenn strlen("f") kleiner als static_buffer_size ist, c_str() static_buffer returned und static_buffer eine kopie von "f" ist.
möglich ist es - aber ich bezweifle, dass es ein compiler macht. er müsste in soviele funktionen gleichzeit sehen um das optimieren zu können...
wäre geil wenn er es könnte - aber solche optimierungen vorauszusetzen ist n bisschen gewagt, zumal noch nichtmal alle compiler NRVO und ähnliches gängige nicht können.
Denn wenn ich
string("s")=="f"
schreibe - dann gehöre ich sowieso geschlagen...Darum gehts ja nicht. Es geht um <unbekannter Wert im Buffer> == string("s").
string("s") == buffer;
ist genauso bescheuert.
-
Du darfst ja nicht vergessen, dass der ganze Geiz höchstwahrscheinlich geinlined wird. Das erleichtert das Optimieren enorm, weil alles direkt an einer Stelle steht und der Compiler so leicht erkennen kann, was unnötig ist.
Natürlich kann man nicht einfach davon ausgehen, dass ein Compiler das macht. Aber ich rechne da schon mit einer einigermaßen hohen Wahrscheinlichkeit. An erster Stelle steht sowieso die Wartung des Codes. Wenn das eine kritische Stelle ist, kann ich dann immer noch Messungen durchführen.string("s") == buffer;
ist genauso bescheuert.Wieso? Finde ich die beste Art, einen C-String mit einem Wert zu vergleichen. Und vor allem wesentlich besser als strcmp(). Mach doch mal bitte nen anderen Vorschlag, vielleicht lern ich was.
Achja und bei nem konstanten Vergleichswert, glaub ich sowieso nicht, dass der Compiler den std::string jedesmal neu konstruiert.
-
Optimizer schrieb:
Du darfst ja nicht vergessen, dass der ganze Geiz höchstwahrscheinlich geinlined wird. Das erleichtert das Optimieren enorm, weil alles direkt an einer Stelle steht und der Compiler so leicht erkennen kann, was unnötig ist.
Natürlich kann man nicht einfach davon ausgehen, dass ein Compiler das macht. Aber ich rechne da schon mit einer einigermaßen hohen Wahrscheinlichkeit. An erster Stelle steht sowieso die Wartung des Codes. Wenn das eine kritische Stelle ist, kann ich dann immer noch Messungen durchführen.Sagmal, liest du das was ich schreibe?
Ich bin von einer ganz simplen implementierung ausgegangen - die es so nie geben wird. Das ganze ist voll mit anderen sachen, zB teilt sich static_buffer und buffer den selben speicher. uU wird das 0 am ende des strings nicht gespeichert, etc.
Das sind situationen wo das wegoptimieren wesentlich komplexer bis unmöglich wird.
denke zB an COW beim VC++ - damit gibt es _garantiert_ dynamisch angeforderten speicher und das ganze wird um eine ebene tiefer versetzt (also mehr funktionen und mehr code == wesentlich komplexer)
string("s") == buffer;
ist genauso bescheuert.Wieso? Finde ich die beste Art, einen C-String mit einem Wert zu vergleichen. Und vor allem wesentlich besser als strcmp(). Mach doch mal bitte nen anderen Vorschlag, vielleicht lern ich was.
strcmp("s", buffer); - was ist daran schlecht?
Da ist genau der Grund warum es strcmp gibt - für exakt diese Situation.Achja und bei nem konstanten Vergleichswert, glaub ich sowieso nicht, dass der Compiler den std::string jedesmal neu konstruiert.
neu wahrscheinlich nicht, aber es wird einmal konstruiert - das ist ein overhead. Ein _sinnloser_ overhead. es bringt dir garkeine vorteile string("s") zu schreiben.
string("s") == buffer
sieht einfach komisch aus - und ich frage mich sofort: warum string("s")? warum ein string objekt erstellen?
bei strcmp("s", buffer) ist mir alles klar.ich schreibe ja auch
strlen(s)
und nicht
string(s).size()
-
Ups? Ich dachte bei string wäre .length() die Länge und nicht size(), was ist length() dann?
-
Mis2com schrieb:
Ups? Ich dachte bei string wäre .length() die Länge und nicht size(), was ist length() dann?
schlechtes design.
length() liefert size() zurück
-
Ich bin von einer ganz simplen implementierung ausgegangen - die es so nie geben wird. Das ganze ist voll mit anderen sachen, zB teilt sich static_buffer und buffer den selben speicher. uU wird das 0 am ende des strings nicht gespeichert, etc.
Kann ich jetzt nicht so ganz nachvollziehen. Bei mir besteht der Konstruktor aus zwei Methodenaufrufen, die auch nicht übermäßig groß ausfallen. Außerdem spielt doch da die Komplexität keine Rolle, das ändert nichts daran, dass ein Compiler IMO keinen Buffer nur zum Lesen und anschließendem Wegwerfen kopieren sollte.
Aber gut, um zum eigentlichen Thema zurückzukommen: Es geht darum, zwei Zeichenketten zu vergleichen. Wie wir ja festgestellt haben, gibt es dafür eigens nen operator== mit const char*. Also frage ich mich jetzt ernsthaft, was aus technischer Sicht dagegen sprechen sollte, die Klasse string zu benutzen.
neu wahrscheinlich nicht, aber es wird einmal konstruiert - das ist ein overhead. Ein _sinnloser_ overhead.
Es ist doch vollkommen egal. Das erinnert mich jetzt spontan an eine Website, auf die ich mal eine Funktion gefunden habe, die OpenGL initialisieren sollte. Für diesen _einmaligen_ Vorgang wurde inline, __fastcall und was auch immer benutzt, völlig schwachsinnig halt. Wenn der String nur _einmal_ konstruiert wird, sehe ich keinen technischen Nachteil.
strcmp("s", buffer); - was ist daran schlecht?
Da ist genau der Grund warum es strcmp gibt - für exakt diese Situation.Nein, strcmp() gibt es, weil die C-Lib Teil der C++ Lib ist und aus keinem anderen Grund.
string("s") == buffer
sieht einfach komisch ausTja, finde ich nicht. Ist wohl sinnlos, darüber Haare zu spalten, weil es einfach Geschmackssache ist.
Auf jeden Fall sehe ich keinen technischen Nachteil und mir gefällt der C++ Weg halt besser. Langsamer ist es ganz offensichtlich nicht (wie du eingangs behauptet hast), also wo genau ist denn das Problem?
-
Compiliert es und guckt euch den Assembler-Output an. Fertig. Spekulieren hilft auch hier wenig.
-
Optimizer schrieb:
Kann ich jetzt nicht so ganz nachvollziehen. Bei mir besteht der Konstruktor aus zwei Methodenaufrufen, die auch nicht übermäßig groß ausfallen.
Ist doch egal wieviele Methodenaufrufe.
Was macht den string intern? wie willst du zB COW wegoptimieren? Weisst du wie das vermutlich implementiert ist?Außerdem spielt doch da die Komplexität keine Rolle, das ändert nichts daran, dass ein Compiler IMO keinen Buffer nur zum Lesen und anschließendem Wegwerfen kopieren sollte.
Es ist mehr als nur ein buffer. du hast uU einen new aufruf (aber nicht immer), strlen(), memcpy() und 2 variablen werden gesetzt. Das ist eine Menge mehr als nur ein temporärer Buffer
Aber gut, um zum eigentlichen Thema zurückzukommen: Es geht darum, zwei Zeichenketten zu vergleichen. Wie wir ja festgestellt haben, gibt es dafür eigens nen operator== mit const char*. Also frage ich mich jetzt ernsthaft, was aus technischer Sicht dagegen sprechen sollte, die Klasse string zu benutzen.
Weil es langsamer ist? Und nicht der Sinn von std::string ist? Und es genau dafür strcmp() gibt?
Es ist doch vollkommen egal. Das erinnert mich jetzt spontan an eine Website, auf die ich mal eine Funktion gefunden habe, die OpenGL initialisieren sollte. Für diesen _einmaligen_ Vorgang wurde inline, __fastcall und was auch immer benutzt, völlig schwachsinnig halt. Wenn der String nur _einmal_ konstruiert wird, sehe ich keinen technischen Nachteil.
Shcreibst du auch
string(s).size() statt strlen() ?Wenn du einmal blödsinn machst, fällt es zwar nicht ins Gewicht - aber du tendierst dann sicher dazu, es immer zu machen wenn du es 'brauchst' und das kann dann recht oft werden.
Sicher, das bisschen bremst nicht wirklich - aber was bekommst du als Gegenleistung? Nichts, eine unintuitives stückchen Code.
Nein, strcmp() gibt es, weil die C-Lib Teil der C++ Lib ist und aus keinem anderen Grund.
Und warum gibt es char* ?
Wenn man char* verwendet - dann muss man auch die dazugehörigen Funktionen verwenden.Stell dir das ganze ein bisschen OO vor:
"hallo".len() == strlen("hallo")
x.copy("hallo") == strcpy(x, "hallo")Wie du siehst gehören diese Funktionen zu den char*
string ist kein Ersatz für char*, sondern eine string Klasse. Wenn man char* verwendet, dann nimmt man die str* Funktionen, wenn man es vermeiden kann die char* zu verwenden, dann nimmt man std::string.Auf jeden Fall sehe ich keinen technischen Nachteil und mir gefällt der C++ Weg halt besser. Langsamer ist es ganz offensichtlich nicht (wie du eingangs behauptet hast), also wo genau ist denn das Problem?
Das Problem ist, dass ich dir zu erklären versuche _warum_ es langsamer ist - aber du nicht hören willst.
@Helium:
ich habe es getestet
-
Was macht den string intern? wie willst du zB COW wegoptimieren? Weisst du wie das vermutlich implementiert ist?
Wenn kein COW verwendet wird (so wie bei mir), stellt sich das Problem nicht?
Außerdem ist COW nicht generell schlecht, mach das mal nicht so runter.Angenommen, COW würde verwendet werden, dann würde ja genau das kopieren, auf das du dich so fixierst, entfallen. Dann müsste das gar nicht erst wegoptimiert werden.
Es ist mehr als nur ein buffer. du hast uU einen new aufruf (aber nicht immer), strlen(), memcpy() und 2 variablen werden gesetzt. Das ist eine Menge mehr als nur ein temporärer Buffer
Ich glaube eher, du willst nicht zuhören. Wenn ein Compiler das Kopieren des Buffers wegoptimiert, dann macht er auch den entsprechenden new Aufruf sowie strlen() und memcpy() nicht mehr, weil das ja genau das Kopieren des Buffers ist. Ist doch echt unpassend, wenn ich sag, der Compiler sollte das wegoptimieren, wenn er einen Buffer nur kopiert, um schnell was drauf zu lesen, dass du dann wieder kommst und sagst, er macht new, er macht strlen() und memcpy(), sorry. Ich weiss schon auch, woraus das Kopieren des Buffers besteht.
Weil es langsamer ist? Und nicht der Sinn von std::string ist? Und es genau dafür strcmp() gibt?
Krass. Wieso soll der operator==(const char*) langsamer sein, obwohl er genauso wie strcmp() nichts anderes macht, als zwei Buffer zu vergleichen??
Und genau dafür gibt es strcmp() in C (ohne ++). Natürlich ist es deshalb kein Verbrechen, strcmp() zu verwenden, aber warum sollte es dann eins sein operator== zu verwenden? Zumal ja auch Stroustrup empfielt, die C-Funktionen zu meiden.string ist kein Ersatz für char*, sondern eine string Klasse.
string wurde aber als Ersatz für char* geschaffen? Genau darum gibt es für alle Funktionen ein passendes Gegenstück. Oder benutzt du auch strcat(), wenn du zwei Zeichenketten verbinden willst, nur weil sie halt gerade als char* vorliegen? Du gewinnst nichts, außer dass du viel leichter nen hard-to-find-bug durch Buffer-Overrun verursachst.
Ich würde ja noch sagen, dass man im Zweifelsfall ein paar Messungen durchführen kann und vielleicht an bestimmten Stellen auf C-Funktionen zurückgreifen kann. Aber du bist anscheinend der Meinung, dass man die C-Funktionen verwenden soll, nur weil man grad was als char* vorliegen hat. Mir ist kein API bekannt, was nicht char* übernimmt oder liefert, allein aus Kompatibilitätsgründen. Trotzdem benutze ich std::string und keine char* 's.
-
Optimizer schrieb:
Angenommen, COW würde verwendet werden, dann würde ja genau das kopieren, auf das du dich so fixierst, entfallen. Dann müsste das gar nicht erst wegoptimiert werden.
Sag mal, reden wir hier vom selben?
Er _muss_ es kopieren, auch bei COW - denn sonst wäre folgendes ein bisschen sehr komisch:char s[]="hallo"; string s2(s); s[1]='e'; cout<<s2;
und schon hat sich s2 verändert...
Ich glaube eher, du willst nicht zuhören.
Teste es einfach, dann siehst du, dass ich recht habe.
Und genau dafür gibt es strcmp() in C (ohne ++).
Blödsinn.
Denn dann gibt es auch keine char* in C (ohne ++).Natürlich ist es deshalb kein Verbrechen, strcmp() zu verwenden, aber warum sollte es dann eins sein operator== zu verwenden?
Weil es um den Faktor 10 langsamer ist?
Zumal ja auch Stroustrup empfielt, die C-Funktionen zu meiden.
Ich glaube du willst nicht verstehe - ich gebe hiermit auf.
verwende einfach was du willst. Ich habe genug erklärt damit jeder der es will verstehen kann - wenn es jemand nicht verstehen will, kann ich auch nix dafür.Ich würde ja noch sagen, dass man im Zweifelsfall ein paar Messungen durchführen kann
Dann mach das doch einfach. Ich habe auf 4 Compilern gemessen - der Unterschied war etwa Faktor 7 bis 11.
Und wenn du
string("s")==buffer
für klarer hältst als
!strcmp("s", buffer)
dann solltest du nochmal n bisschen lernen gehen.wenn man buffer als char* hat - dann hat man sich bereits entschieden char* zu verwenden, sonst würde ich ja gleich eine ordentliche klasse verwenden.