define oder const std::string
-
Guten Morgen!
Ich überlege gerade ob ich diverse defines, wie
#define ROOT_ELEM "root"
gegen
const std::string ROOT_ELEM("root");
tauschen sollte.
Meine Überlegung ist deshalb, weil sehr viele String-Vergleiche mit diesen "defines" gemacht werden und vermutlich ein std::string Verlgeich performanter ist als strcmp (oder?)Gibt es noch weitere Sachen die ich berücksichtigen sollte? Oder sollte ich es eher so lassen wie es ist?
Danke!
lg
-
(constexpr) char const ROOT_ELEM[] = "root";
-
constdefine schrieb:
Meine Überlegung ist deshalb, weil sehr viele String-Vergleiche mit diesen "defines" gemacht werden und vermutlich ein std::string Verlgeich performanter ist als strcmp (oder?)
Hängt davon ab, was genau du machst, aber rein prinzipiell wirds performancemäßig hier kaum einen Unterschied geben. Überhaupt: Wenn die Performance von Stringvergleichen zum Problem wird und du nicht gerade an einer Textverarbeitung bastelst, dann machst du sehr wahrscheinlich ganz grundlegend wo was falsch...
constdefine schrieb:
Gibt es noch weitere Sachen die ich berücksichtigen sollte? Oder sollte ich es eher so lassen wie es ist?
Mach es so, wie Kellerautomat gezeigt hat
const char ROOT_ELEM[] = "root";
#define
ist böse und zu vermeiden, so gut es nur geht.
-
Kellerautomat schrieb:
(constexpr) char const ROOT_ELEM[] = "root";
Das funktioniert jetzt wie ohne strcmp?
-
Danke für die Antwort.
Leider kann ich noch kein C++11 verwenden.
Darf man erfahren warum genau diese Art vorzuziehen ist?
-
constdefine schrieb:
Gibt es noch weitere Sachen die ich berücksichtigen sollte? Oder sollte ich es eher so lassen wie es ist?
Da du strcmp benutzen musst, sind deine anderen Strings wohl ebenfalls char* statt std::string. Das solltest du dringend ändern.
-
constdefine schrieb:
Leider kann ich noch kein C++11 verwenden.
Dann lass einfach das
(constexpr)
weg.constdefine schrieb:
Darf man erfahren warum genau diese Art vorzuziehen ist?
Weil du so eine Stringkonstante definierst. #define tut nur Text ersetzen, d.h. effektiv das selbe wie Suchen und Ersetzen in deinem Texteditor: Überall, wo ROOT_ELEM steht, wird einfach dein "root" hingeschrieben. Das passiert im Präprozessor, vor dem eigentlichen Compiler. Solche Makros sind nicht sehr elegant, berücksichtigen keine Namensräume und können sehr leicht zu extrem schwer zu findenden Bugs und Fehlern führen...
-
dot schrieb:
Mach es so, wie Kellerautomat gezeigt hat
const char ROOT_ELEM[] = "root";
Mach es auf keinen Fall so, weil das viel zu gefährlich ist.
std::end(ROOT_ELEM)
zeigt an eine unerwartete Stelle.
Jemand wird die Länge mitsizeof
bestimmen, was dann still kaputt geht, wenn im Jahr 2101 endlich aufstd::string
gewechselt wird.
Vergleichen muss man wieder mitstrcmp
.
-
TyRoXx schrieb:
std::end(ROOT_ELEM)
zeigt an eine unerwartete Stelle.Auf eins hinter dem Nullbyte? Inwiefern ist das unerwartet?
Jemand wird die Länge mit [c]sizeof[/c] bestimmen, was dann still kaputt geht, wenn im Jahr 2101 endlich auf [c]std::string[/c] gewechselt wird.
Jemand der die Länge mit sizeof besimmt, muss eh eins abziehen. Und wieso sollte auf std::string gewechselt werden? std::string hat dynamische Speicherallozierung, das ist hier absolut unnötig.
Vergleichen muss man wieder mit
strcmp
.Es sei denn man vergleicht eins mit std::string.
Die bessere Lösung wäre aber einfach:
const char *root_elem = "root";
Wieso braucht man ein konstantes Array, da kann man gleich den nativen Pointer verwenden. Plus, der sizeof Trick, über den sich TyRoXx aufgeregt hat, geht nicht mehr.
-
dot schrieb:
Hängt davon ab, was genau du machst, aber rein prinzipiell wirds performancemäßig hier kaum einen Unterschied geben.
Hmm das verwundert mich, weil wenn die Strings eine unterschiedliche Länge haben, dann sollte doch der std::string Vergleich schneller sein, oder?
Es nicht so, dass es zu einem Problem geworden ist, aber wenn man bei ständigen Überprüfungen (eigener Thread) sich irgendwo was sparen kann, dann nehme ich das gerne mit.manni66 schrieb:
Das funktioniert jetzt wie ohne strcmp?
Es muss nicht unbedingt strcmp verwendet werden, kann natürlich auch auf den Vergleichsoperator von std::string umgestellt werden.
manni66 schrieb:
constdefine schrieb:
Gibt es noch weitere Sachen die ich berücksichtigen sollte? Oder sollte ich es eher so lassen wie es ist?
Da du strcmp benutzen musst, sind deine anderen Strings wohl ebenfalls char* statt std::string. Das solltest du dringend ändern.
Nein es werden zu ca 80% std::string für den Vergleich angewendet.
dot schrieb:
Weil du so eine Stringkonstante definierst.
Dann verstehe ich nicht, warum ich const std::string nicht verwenden soll, weil so hätte ich die Zeichenkettenlänge auch schon dabei und muss nicht immer berechnet werden.
dot schrieb:
#define tut nur Text ersetzen, d.h. effektiv das selbe wie Suchen und Ersetzen in deinem Texteditor: Überall, wo ROOT_ELEM steht, wird einfach dein "root" hingeschrieben. Das passiert im Präprozessor, vor dem eigentlichen Compiler. Solche Makros sind nicht sehr elegant, berücksichtigen keine Namensräume und können sehr leicht zu extrem schwer zu findenden Bugs und Fehlern führen...
Echt so ein Zeichenkettem-define kann zu einem schwer zu findenden Bug führen? Danke für den Hinweis, hätte ich nicht vermutet.
Hmm ev. sollte ich die Fragestellung ändern!
Früher hat man wohl oft mit defines gearbeitet (also bei uns im Code ist es leider so), wie würde es man es nun machen (ohne das man Rücksicht auf den alten code, strcmp usw nimmt)?
-
Hmm das verwundert mich, weil wenn die Strings eine unterschiedliche Länge haben, dann sollte doch der std::string Vergleich schneller sein, oder?
Theoretisch.
Dann verstehe ich nicht, warum ich const std::string nicht verwenden soll
Sollst du doch!
-
Was ich noch nicht verstanden habe: Hast Du viele von diesen
#define
s?
Oder gibt es viele Vergleiche?
Oder beides?
-
constdefine schrieb:
dot schrieb:
Weil du so eine Stringkonstante definierst.
Dann verstehe ich nicht, warum ich const std::string nicht verwenden soll, weil so hätte ich die Zeichenkettenlänge auch schon dabei und muss nicht immer berechnet werden.
Die Länge einer Stringkonstante ist eine Compiletime-Konstante, die du einfach mit
sizeof
bekommst:template <size_t N> inline strlen(const char (&str)[N]) { return N - 1; } const char bla[] = "hello world!"; auto l = strlen(bla);
Nathan schrieb:
Die bessere Lösung wäre aber einfach:
const char *root_elem = "root";
Wieso braucht man ein konstantes Array, da kann man gleich den nativen Pointer verwenden. Plus, der sizeof Trick, über den sich TyRoXx aufgeregt hat, geht nicht mehr.Was genau du mit dem "nativen Pointer" meinst, ist mir unklar. Jedenfalls ist das imo keine gute Lösung, weil es keine Stringkonstante mehr ist und eine völlig sinnlose Indirektion einführt...
constdefine schrieb:
dot schrieb:
#define tut nur Text ersetzen, d.h. effektiv das selbe wie Suchen und Ersetzen in deinem Texteditor: Überall, wo ROOT_ELEM steht, wird einfach dein "root" hingeschrieben. Das passiert im Präprozessor, vor dem eigentlichen Compiler. Solche Makros sind nicht sehr elegant, berücksichtigen keine Namensräume und können sehr leicht zu extrem schwer zu findenden Bugs und Fehlern führen...
Echt so ein Zeichenkettem-define kann zu einem schwer zu findenden Bug führen? Danke für den Hinweis, hätte ich nicht vermutet.
Gute Zusammenfassung wieso Makros nicht so toll sind: http://stackoverflow.com/questions/14041453/why-are-preprocessor-macros-evil-and-what-are-the-alternatives
constdefine schrieb:
Hmm ev. sollte ich die Fragestellung ändern!
Früher hat man wohl oft mit defines gearbeitet (also bei uns im Code ist es leider so), wie würde es man es nun machen (ohne das man Rücksicht auf den alten code, strcmp usw nimmt)?Heute benutzt man const und Funktionen...
Arcoth schrieb:
Dann verstehe ich nicht, warum ich const std::string nicht verwenden soll
Sollst du doch!
Nein. Von
std::string
für Stringkonstanten ist imo definitiv abzuraten. Verwendstd::string
für Stringvariablen, aber nicht für Konstanten, weil:Nathan schrieb:
std::string hat dynamische Speicherallozierung, das ist hier absolut unnötig.
Bingo
-
dot schrieb:
Von
std::string
für Stringkonstanten ist imo definitiv abzuraten. Verwendstd::string
für Stringvariablen, aber nicht für Konstanten, weil:Nathan schrieb:
std::string hat dynamische Speicherallozierung, das ist hier absolut unnötig.
Bingo
Und weiter?
char
-Arrays oder Zeiger sind viel schlimmer, weil die messbare Kosten in Form von Fehlersuche verursachen.
Wennstring
zu teuer ist, nimmt man eben irgendeinstring_view
-Gedöns. Aber doch nicht nackte Zeiger oder Arrays.
-
TyRoXx schrieb:
char
-Arrays oder Zeiger sind viel schlimmer, weil die messbare Kosten in Form von Fehlersuche verursachen.Ist das so? Ich zumindest kann das aus meiner Erfahrung im konkreten Fall von Stringkonstanten nicht bezeugen...
-
dot schrieb:
TyRoXx schrieb:
char
-Arrays oder Zeiger sind viel schlimmer, weil die messbare Kosten in Form von Fehlersuche verursachen.Ist das so? Ich zumindest kann das aus meiner Erfahrung im konkreten Fall von Stringkonstanten nicht bezeugen...
Früher mal waren Stringliterale nicht const, da konnte man hübsch Code bauen, der im Debug-Modus läuft und im Releasemodus schutzfehlert oder andere Stringliterale zerdeppert. Ist mir aber nur einmal passiert bei einem Wettbewerb um möglichst wenige Tokens.
Jetzt sehe ich null Problemo bei char const*.Was macht man damit ist die Frage? Nur ein char const*, um ihn dann eh in einen fstream-Konstruktor zu stecken? Den nehme ich gerne. Der fstream muss ja dann doch einen char const* ans BS runterschicken, der std::string wäre nur ein Umweg.
Ebenso mit "root", wenns im, Baum doch nur eine root gibt und nur ein einziger Baum gebaut wird.
Anders, wenn ich davon viele Kopien ziehen will und in std::strings stecken, dann ein std::string const.
-
@Tyrox:
boost::const_string
?
-
Furble Wurble schrieb:
Was ich noch nicht verstanden habe: Hast Du viele von diesen
#define
s?
Oder gibt es viele Vergleiche?
Oder beides?Beides.
Es sind ca. 30 #defines und sehr viele Vergleiche (man kann sich das so vorstellen wie einen Parser der ein XML durchläuft und div. Werte rauspickt und da habe ich auf der einen Seite die angesprochenen #defines und auf der anderen Seite div. std::string die verglichen werden müssen)dot schrieb:
Die Länge einer Stringkonstante ist eine Compiletime-Konstante, die du einfach mit
sizeof
bekommst:template <size_t N> inline strlen(const char (&str)[N]) { return N - 1; }
Sollte das auch in strcmp funktionieren (falls dort eine Längenberechung gemacht wird), weil anhand
extern int strcmp (const char *__s1, const char *__s2);
werden ja const char* übergeben.
(kann auch sein, dass ich mich hier nun total zu wenig in c++ auskenne)dot schrieb:
Gute Zusammenfassung wieso Makros nicht so toll sind: http://stackoverflow.com/questions/14041453/why-are-preprocessor-macros-evil-and-what-are-the-alternatives
DANKE! sehr interessant!
-
constdefine schrieb:
Furble Wurble schrieb:
Was ich noch nicht verstanden habe: Hast Du viele von diesen
#define
s?
Oder gibt es viele Vergleiche?
Oder beides?Beides.
Es sind ca. 30 #defines und sehr viele Vergleiche (man kann sich das so vorstellen wie einen Parser der ein XML durchläuft und div. Werte rauspickt und da habe ich auf der einen Seite die angesprochenen #defines und auf der anderen Seite div. std::string die verglichen werden müssen)Ich frag mich ja, wieso das überhaupt explizit definierte Konstanten sein müssen, die sollten idealerweise ja sowieso nur einmal im Code vorkommen? Anyways: Verwend einfach die
compare
methode vonstd::string
, der kannst du die Konstante und deren Länge geben...
-
dot schrieb:
Ich frag mich ja, wieso das überhaupt explizit definierte Konstanten sein müssen, die sollten idealerweise ja sowieso nur einmal im Code vorkommen?
Wenn ich mich recht erinnere, machte ich früher
const char* configFileName="vla"; ... void tuEs(){ //wichtige Sachen ifstream config(configFileName);//und von hier while(config>>line){ //parse parse parse if(key=="run"){ tuEsEndlich(value); //bis hier an Dutzenden Codestellen Copy&Paste } //code ist schon viel zu riesig, das Wisssen, daß das configFole "vla" heißt, rauszuhalten, hilft zur Übersicht. Jeder Strohhalm hilft. Ehrlich!
und viel später
map<string,string> config=readConfig("vla"); ... void tuEs(){ tuEsEndlich(config["run"]); }
Tja, früher war Speicher sehr teuer. Als SPeicher kein Problem mehr war, wars die Startzeit. Alte Acrobat-Reader mit 60 Sekunden Startzeit. Also
map<string,string> config=readConfig("vla"); ... void tuEs(){ tuEsEndlich(TheConfigManager.getInstance("run"));//lazy }
Mal mein Rechnerkaufverhalten anschauend prognostiziere ich, daß in den nächsten 20 Jahren der Trend im Programmieren von Speichersparen und Zeitsparen weggeht zu stromsparenden Datenstrukturen. Apps werden im Katalog angeben, wieviel Akku(*) sie auf den wichtigsten drei Referenzplattformen wegfressen im Idle und unter normaler Benutzung.
(*) Also eigentlich Wattstunden pro Stunde oder Watt, aber die Leute werden sich schon auf was komplett irrsinniges einigen wie…
wie…
Da hab ich einfach keine Phantasie, was wäre für den Endkunden einfacher als Watt? Der muss doch nicht wissen, was ein Watt so genau ist, sondern nur: Je mehr, desto schlechter. Ich verwette meinen Hut, daß man sich auf eine so unirdische Einheit einigen wird, daß ALLE Beteiligten drüber fluchen werden: Die Hersteller, die Verkäufer und die Kunden.