Set- und Getterfunktionen verwenden oder nicht?
-
NewSoftzzz schrieb:
Hallo?? Hast du dir überhaupt mal den Kontext angeguckt?
class.parse( "Hello.txt" );DARUM ging es die ganze Zeit. Das ist ja wohl ganz offensichtlich immer das gleiche Argument, oder? Und wenn parse nun einen "const std::string&" als Parameter hat, dann dort IMMER einen "static const std::string" benutzen. Jetzt klar?
Ja klar, und ich wollte mit dem Codefetzen nur zeigen, dass die Übergabe eines std::string in dem Fall Mist ist, da ich da nur nen temporären std::string erzeuge, nur um dem ifstream einen std::string::c_str() zu geben.
Eben weil in diesem Falle die verwendete Bibliothek (libstdc++) nur ein Interface für const char* anbietet und nicht für std::string.
In jenem Kontext ist auch klar, dass es nicht darauf hinauslaufen wird, dass sehr oft immer wieder die selbe Datei geöffnet wird. Und in jenem Kontext ist auch nicht das Konstruieren eines temporären std::string-Objektes die Performancebremse, sondern es sind die Zugriffe auf die Festplatte.Ich verstehe dich durchaus, dass du bei Aufrufen, bei denen sich ABSOLUT NIEMALS das Argument ändert, ein static const std::string nützlich sein kann. Aber so viele Fälle sind das nicht, und wenn doch dann hast du ziemlich viele Strings im Speicher liegen.
Und ich denke nicht, dass man beim Verzichten auf static const std::string jetzt so viel Ausführzeit spart. Wenn es Zeitkritisch wird, muss man sowieso alles vor dem kritischen Part konstruiert haben, denn Kopieren, Zuweisen, neu erstellen usw. bremst da schonmal gewaltig. Aber static const braucht man in den Bereichen dann trotzdem nicht (wirklich immer).
Ich denke aber die Diskussion geht ziemlich am eigentlichen Anliegen des Posts vorbei, nämlich Sinn und Unsinn von gettern/settern.
-
l'abra d'or schrieb:
Ich verstehe dich durchaus, dass du bei Aufrufen, bei denen sich ABSOLUT NIEMALS das Argument ändert, ein static const std::string nützlich sein kann. Aber so viele Fälle sind das nicht, und wenn doch dann hast du ziemlich viele Strings im Speicher liegen.
Und ich denke nicht, dass man beim Verzichten auf static const std::string jetzt so viel Ausführzeit spart. Wenn es Zeitkritisch wird, muss man sowieso alles vor dem kritischen Part konstruiert haben, denn Kopieren, Zuweisen, neu erstellen usw. bremst da schonmal gewaltig. Aber static const braucht man in den Bereichen dann trotzdem nicht (wirklich immer).
Ich hatte einen MMORPG Server programmiert, also eine Echtzeitapplikation. Dort gab es pro Sekunde ca. 10.000 - 100.000 solcher Methodenaufrufe und die Umstellung von c-strings auf static const std::strings hat was gebracht.
l'abra d'or schrieb:
Aber so viele Fälle sind das nicht, und wenn doch dann hast du ziemlich viele Strings im Speicher liegen.
Ja, aber die liegen als C-Strings ja auch im Speicher rum. Übrigens sind das nicht unbedingt viele, sondern die werden einfach nur sehr sehr oft pro Sekunde aufgerufen (Bei einem MMORPG gibt es recht viele Textbausteine, die immer gleich sind usw.).
Was ich hier erzähle ist also nicht irgendein Theoriekram, sondern das hab ich im harten praktischen Leben so gelernt.
mfg, René~
-
Nur ganz kurz:
Du hattest da also einen Spezialfall: Echtzeitanwendung! Also keine normale Standard0815-Anwendung, wo dieser "Oberhead" tatsächlich irrelevant sein sollte.
Deine Textbausteine können wohl auch länger sein, also nicht ein Pfad/Name, der in 5-60 chars passt.
In meinen Augen zu speziell um eine allgemeine Programmierregel daraus zu machen. Für deinen Fall ist sie aber durchaus sinnvoll.
-
l'abra d'or schrieb:
In meinen Augen zu speziell um eine allgemeine Programmierregel daraus zu machen. Für deinen Fall ist sie aber durchaus sinnvoll.
Warum daraus keine allgemeine Regel machen? Ich seh nämlich nur den Performancevorteil, aber keine Nachteile..
Nenn mir einen Nachteil für diesen Fall?
Also, wenn du keinen Nachteil nennen kannst, dann => Allgemeine Programmierregel (außer vllt. Embedded, weil ein std::string sizeof(size_t) mehr bytes braucht als der c-string).
mfg, René
-
@NewSoftzzz
Warum rufst du eigentlich eine Funktion derart oft pro Sekunde mit immer denselben Strings auf? Soll heißen, warum nicht etwa enums.In den meisten Fällen ist die Stringliteral -> std::string-Konvertierung vernachlässigbar. Eine Dateiladefunktion ist doch Paradebeispiel. Die Laufzeit, die du mit const char* bzw. statischen Strings (natürlich auch nur bei gleichbleibendem Dateinamen...) bei allen Programmdurchläufen auf allen Rechnern weltweit zusammengezählt sparen wirst, wird wohl weit unter der Zeit liegen, die du für das Tippen von den zusätzlichen .c_str() bzw. static std::strings aufbringen musst.
-
NewSoftzzz schrieb:
Ach, wenn es dir so wichtig ist :p
Den wichtigen Teil hast du nicht berücksichtigt.
Nexus schrieb:
Naja. Entweder man lädt eine Datei einmal, und dann spielt es sicher keine Rolle, ob ein temporäres
std::string-Objekt erstellt wird oder ein statisches. Oder man lädt häufig Dateien, wobei aber die Wahrscheinlichkeit gross ist, dass es sich um verschiedene handelt. Und dann ist man mit dem konstanten String wieder aufgeschmissen.Mir ist natürlich klar, dass es bei etlichen Aufrufe pro Sekunde mit dem gleichen Argument ratsam sein könnte, das Argument zu speichern. Das gilt auch nicht speziell für
std::string, sondern ist Bestandteil der wohl universellsten Optimierungsstrategie, nämlich unnötige Berechnungen und Konstruktionen zu vermeiden.Jedoch rechtfertigt dieser Ausnahmefall – warum das normalerweise nicht die Regel darstellt, wurde ja erklärt – keineswegs Pauschalisierungen wie "man sollte immer statische Strings anlegen, statt temporäre Objekte zu übergeben". l'abra d'or hat einige daraus entstehende Nachteile schön erläutert.
Um konsequent zu sein, solltest du deine Programmierregel auch in sehr vielen anderen Zusammenhängen anwenden, weil es ja schliesslich sein könnte, das mehrmals nacheinander das gleiche Objekt übergeben wird. Das würde den notwendigen Code aber vervielfachen und verschleiern, während der tatsächliche Performancegewinn eher im Hintergrund stehen dürfte.
-
;Athar schrieb:
@NewSoftzzz
Warum rufst du eigentlich eine Funktion derart oft pro Sekunde mit immer denselben Strings auf? Soll heißen, warum nicht etwa enums.class Player { public: void sendMessageToPlayer(const std::string& message); }; Game::CheckAction(...) { if(illegal) sendMessageToPlayer("Sorry, not possible."); }Soll ich hier etwas die sendMessage Funktion duplizieren, einmal für enums und einmal für normale Strings? Nein, ich denke nicht.
Übrigens hat l'abra d'or bisher keine Nachteile genannt, weil wir aneinander vorbeigeredet haben und er was ganz anderes meinte...
Nexus schrieb:
Um konsequent zu sein, solltest du deine Programmierregel auch in sehr vielen anderen Zusammenhängen anwenden, weil es ja schliesslich sein könnte, das mehrmals nacheinander das gleiche Objekt übergeben wird. Das würde den notwendigen Code aber vervielfachen und verschleiern, während der tatsächliche Performancegewinn eher im Hintergrund stehen dürfte.
Ein static std::string verschlechtert aber nicht die Lesbarkeit.. Und der Performanceunterschied ist DRASTISCH, ich muss wohl heute oder morgen nochmal nen Benchmark schreiben, um euch zu überzeugen...
mfg, René
-
Wer schickt denn bitte statische Strings von einem Server zu einem Client. Wäre viel einfacher und effizienter in so einem Fall einen Error Code zu verschicken. Dann kann auch der Fehler in der Sprache angezeigt werden, welche der Client ausgewählt hat. Zudem dürfte sowas auch die Verbindung entlasten, da viel weniger übermittelt werden muss.
-
[Ghost] schrieb:
Wer schickt denn bitte statische Strings von einem Server zu einem Client. Wäre viel einfacher und effizienter in so einem Fall einen Error Code zu verschicken. Dann kann auch der Fehler in der Sprache angezeigt werden, welche der Client ausgewählt hat. Zudem dürfte sowas auch die Verbindung entlasten, da viel weniger übermittelt werden muss.
Der Client war damals nicht von mir, war ein fertig kompilierter Client von nem anderen Spiel ohne Source Code

Jetzt weißt du, wer sowas macht, Leute, die den Client nicht ändern können

mfg, René~
-
NewSoftzzz schrieb:
Ein static std::string verschlechtert aber nicht die Lesbarkeit..
Nein, natürlich nicht.
static std::string String; String = CharArray; Function(String);vs.
Function(CharArray);P.S.: Denk dran, deine Aussage war:
NewSoftzzz schrieb:
Ich meinte nur generell, jede Funktion, die eine std::string Referenz als Parameter hat, sollte man mit nem statischen std::string aufrufen.
-
Nexus schrieb:
static std::string String; String = CharArray; Function(String);vs.
Function(CharArray);Tzzt, Tzzt..
Wenn, dann sieht das so aus:
const static std::string sorryNotPossibleString = "Sorry, Not Possible."; Function(sorryNotPossibleString);vs.
Function("Sorry, Not Possible.");Und das für einen Bruchteil der CPU Zeit, das isses Wert.
mfg, René~
-
NewSoftzzz schrieb:
Jetzt weißt du, wer sowas macht, Leute, die den Client nicht ändern können

Deine Erkenntnis beruht immer wie mehr auf eine sehr spezielle Situation.

Im übrigen:
Was machtsendMessageToPlayer? Braucht die Funktion überhaupt einenstd::string? Würde nicht auch einchar const*reichen?
-
NewSoftzzz schrieb:
Tzzt, Tzzt..
Wenn, dann sieht das so aus:
Äh, ja. Rate mal, warum ich dich nochmals an deine Aussage erinnert habe. Du hast die Allgemeingültigkeit sogar speziell betont. Um das nochmals zu markieren:
NewSoftzzz schrieb:
Ich meinte nur generell, jede Funktion, die eine std::string Referenz als Parameter hat, sollte man mit nem statischen std::string aufrufen.
Und sowas ist einfach alles andere als sinnvoll. Wenn du das nicht so gemeint hast, dann formuliere es nächstes Mal anders. Wenn dir ein Fehler passiert, kannst du ja immer noch nachträglich dazu Stellung nehmen.
(Dazu kämen all die anderen unsinnigen Fälle wie der folgende, welche von dieser Aussage eingeschlossen werden. Ich glaube dir gerne, dass du das nicht so machst, aber dann relativiere solche Sätze bitte. Tut mir leid für die Haarspalterei, doch du scheinst deinen Fehler bisher nicht einzusehen.)
static std::string String; String = OtherString; // OtherString ist nicht-statischer std::string Function(String); // Funktion muss aber mit statischem String aufgerufen werdenNewSoftzzz schrieb:
Und das für einen Bruchteil der CPU Zeit, das isses Wert.
Nochmals: Die Fälle, in denen man eine Funktion (z.B. Datei-Laden) derart oft mit dem gleichen Argument aufruft, dass es tatsächlich performancekritisch werden könnte, sind Ausnahmen. Und natürlich würde ich das Argument dort auch zwischenspeichern (ob
staticdafür angebracht ist, hängt von der Situation ab). Aber ich wiederhole mich.
-
NewSoftzzz schrieb:
Soll ich hier etwas die sendMessage Funktion duplizieren, einmal für enums und einmal für normale Strings? Nein, ich denke nicht.
Nö, hier mache enums natürlich keinen wirklichen Sinn. Allerdings musst du sowas sicher auch nicht zehntausende Male pro Sekunde schicken. Es sei denn, die ganze Server/Client-Kommunikation läuft in Textform ab.
Was hier übrigens mehr Sinn macht, ist der Haupt-sendMessageToPlayer-Funktion const char* und die Länge des Strings als Parameter zu geben. Da sie wahrscheinlich außer Kopieren oder an send() übergeben nichts mehr mit dem String macht, kannst du auf std::string-Funktionen dort verzichten. Und dann jeweils zwei überladene Funktionen sendMessageToPlayer(const std::string&) und sendMessageToPlayer(const char*), welche dir Ursprungsfunktion mit den richtigen Parametern aufrufen. Dann brauchst du das static string-Gedöns nicht mehr, denn strlen in der zweiten überladenen Funktion kann zur Kompilierzeit ausgewertet werden.
-
[Ghost] schrieb:
Was macht
sendMessageToPlayer? Braucht die Funktion überhaupt einenstd::string? Würde nicht auch einchar const*reichen?Darum geht's doch gar nicht! Ist doch scheiß egal, ob man die FUNKTION auch anders machen kann, wir reden hier von nem zur Compilezeit feststehenden String, den man an ne Methode übergibt, die ne std::string Referenz haben will. Die Frage ist hier nur, c-string oder static std::string.
Nexus schrieb:
Du hast die Allgemeingültigkeit sogar speziell betont. Um das nochmals zu markieren:
NewSoftzzz schrieb:
Ich meinte nur generell, jede Funktion, die eine std::string Referenz als Parameter hat, sollte man mit nem statischen std::string aufrufen.
Und sowas ist einfach alles andere als sinnvoll.
Und dazu stehe ich auch jetzt noch. Es IST allgemeingültig, dafür ist der Performanceunterschied einfach zu hoch, dass die EINE Zeile mehr Code OHNE IRGENDWELCHE Nachteile nicht benutzt werden sollte!!! Siehe benchmark.
Benchmark fertig:
#include <sys/time.h> struct timeval tv; int myint; void benchmark(const std::string& input) { myint += input.size(); } int main() { gettimeofday(&tv, NULL); uint64_t start = tv.tv_sec*1000 + (tv.tv_usec / 1000); myint = 0; for(uint64_t i=0; i< 100 * 1000 * 1000; i++) benchmark("This is for all the nonbelievers out there, who think that they shouldn't follow this rule."); gettimeofday(&tv, NULL); uint64_t end = tv.tv_sec*1000 + (tv.tv_usec / 1000); std::cout << myint << ": " << (end - start) << std::endl; gettimeofday(&tv, NULL); start = tv.tv_sec*1000 + (tv.tv_usec / 1000); myint = 0; static const std::string messageToNonbelievers = "This is for all the nonbelievers out there, who think that they shouldn't follow this rule."; for(uint64_t i=0; i< 100 * 1000 * 1000; i++) benchmark(messageToNonbelievers); gettimeofday(&tv, NULL); end = tv.tv_sec*1000 + (tv.tv_usec / 1000); std::cout << myint << ": " << (end - start) << std::endl; }Ergebnis:
510065408: 12735
510065408: 775Faktor 16,4 !!!
Und das ist noch nicht mal der komplette Faktor, da ja ein Großteil der Ressourcen für die Schleife, den Funktionsaufruf, die Addierung der size() etc. draufgeht. Und trotzdem haben wir einen Faktor von 16,4! Der komplette Funktionsaufruf braucht 16,4 mal mehr so lange! Und das nur weil man statt "const static std::string" einen c-string benutzt.
Also mal ehrlich Jungs, seht es ein, die eine Zeile Code ist hier völlig gerechtfertigt und macht bei nem Variablennamen, der den String zusammenfasst, den Code auch nicht unleserlicher.
Nexus schrieb:
Tut mir leid für die Haarspalterei, doch du scheinst deinen Fehler bisher nicht einzusehen.
16,4 fache Ausführungszeit, nur damit man eine Zeile Code einsparen kann? Und das OHNE JEDEN VORTEIL, nur um etwas weniger Code tippen?? Da kann ich auch direkt PHP programmieren.
SRSLY?
Wer sieht seinen Fehler nicht ein?
mfg, René~
-
@NewSoftzzz
Das Ergebnis ist nur insofern verwunderlich, dass der Unterschied so gering ist. Im ersteren Fall dürfte der gesamte benchmark-Aufruf auf eine, höchstens zwei Assemblerinstruktionen reduziert werden können, im zweiten Fall muss mit new neuer Speicher für eine Stringkopie angefordert werden und dann eben noch kopiert werden.
Ist aber nicht der Punkt, denn außer in diesem Testprogramm reduziert sich dadurch keine Laufzeit ums 16-fache. Außer in Situationen, wo intensiv mit Strings gearbeitet wird, wird der Unterschied nämlich nicht messbar, geschweige denn spürbar sein (also z.B. bei Verwendung in einer Dateiladefunktion).
Wenn du aber eine möglichst performante Verarbeitung von Stringliteralen benötigst, dann liegt es nahe, eine entsprechende Schnittstelle anzubieten, wie ich ja schon vorher gesagt habe. Extrazeilen mit static std::string sind dann ebenfalls nicht nötig.
-
Korrekturen: zweiten*, ersten*
-
;Athar schrieb:
Wenn du aber eine möglichst performante Verarbeitung von Stringliteralen benötigst, dann liegt es nahe, eine entsprechende Schnittstelle anzubieten, wie ich ja schon vorher gesagt habe. Extrazeilen mit static std::string sind dann ebenfalls nicht nötig.
Warum immer so sinnlose Argumente?
ich: "Was ist besser, Apfel oder Birne?"
du: "Schluck eine Vitamintablette, ist effizienter."WTF? Es ist doch scheiß egal, warum die Methode einen "const std::string&" Parameter hat, sie HAT ihn einfach. PUNKT.
Und die Frage lautet bei einer solchen Methode wenn der string schon zur Compilezeit feststeht:
"c-string-literal oder const static std::string"Und die Antwort lautet IMMER:
"const static std::string"Wer jetzt noch widerspricht, bitte Nachteile nennen oder Gegenteil beweisen.
mfg, René~
-
NewSoftzzz schrieb:
Und die Frage lautet bei einer solchen Methode wenn der string schon zur Compilezeit feststeht:
"c-string-literal oder const static std::string"Und die Antwort lautet IMMER:
"const static std::string"Nein, eben nicht! Hast du meinen Post auch nur gelesen?
Die Antwort lautet BEIDES. Wieso weigerst du dich, zwei Zeilen hinzuzufügen, die das Problem endgültig aus der Welt schaffen und bereicherst stattdessen alle möglichen sendMessageToPlayer-Aufrufe mit einer Extrazeile? Vor allem, weil es davon wahrscheinlich nicht wenige geben wird.
-
Athar schrieb:
Wieso weigerst du dich, zwei Zeilen hinzuzufügen, die das Problem endgültig aus der Welt schaffen
DIE METHODE/KLASSE KANN NICHT GEÄNDERT WERDEN.
LERN LESEN!mfg, René~