zeichenketten.html | |||||||||||||||||||||||||||||||||||||||||||||||
Sprachen »de« en Benutzerkonto
|
Zeichenketten (strings): char * oder std::string?Es stellt sich die Frage, ob für Zeichenketten std::string aus der C++ Standard Template Library verwendet werden soll, oder doch lieber der traditionelle "char *" Pointer. Für std::string spricht die einfachere Programmierung (der Programmierer muss sich nicht um die Allokation von Speicher kümmern) und die Immunität gegen Bufferoverruns, was die Sicherheit verbessert. Aber wie viel langsamer ist die Verwendung von std::string? Und wie viel RAM wird bei beiden Versionen gebraucht? Geschwindigkeitsvergleich Stringerzeugung und -löschungIm ersten Beispielprogramm wird 1000 mal dynamisch ein std::string Objekt erzeugt und eine Zeichenkette zugewiesen. Optional kann die Zeichenkette jedes Mal ausgegeben werden. Nach jedem Durchlauf wird die Zeichenkette wieder gelöscht.#include <iostream> #include <string> int main(){ long int i; std::string *text; for (i=0;i<1000;i++){ text = new std::string; *text = "The quick brown fox jumped over the lazy dog"; #ifdef OUTPUT std::cout << *text << std::endl; #endif delete text; } } Im zweiten Beispielprogramm wird statt dem std::string ein char * verwendet und mit malloc() Speicher Zugewiesen. #include <iostream> #include <malloc.h> #include <string.h> int main(){ long int i; char *text; for (i=0;i<1000;i++){ text = (char *) malloc(50); strncpy(text,"The quick brown fox jumped over the lazy dog",50); #ifdef OUTPUT std::cout << text << std::endl; #endif free(text); } }Die beiden Programme werden mit verschiedenen Optionen kompiliert und mit "time" auf ihre Performance getestet. Bei der Version mit Output wird die Ausgabe auf der Kommandozeile nach /dev/null umgeleitet. Der verwendete Compiler ist ein gcc Version 3.3.5, libc6 Version 2.3.2 Resultate auf einem i486, 33MHz, 48MB Speicher:
Es zeigt sich, dass die Erzeugung und Löschung von std::string nur wenige Prozent länger dauert als bei char *, und dass selbst auf einem langsamen Rechner hunderte std::strings pro Sekunde erzeugt und gelöscht werden können. Schaltet man den Output zu, so wird die Zeit zur Erzeugung und Löschung der Strings beinahe irrelevant. Es bleibt zu prüfen, wie sich std::string bei komplexeren Stringoperationen wie Vergleichen, Suche im String oder zusammenfügen von zwei Strings verhält. Geschwindigkeitsvergleich StringverknüpfungVersion mit std::string#include <iostream> #include <string> int main(){ long int i; std::string *text; std::string fulltext; for (i=0;i<1000;i++){ text = new std::string; *text = "The quick brown fox jumped over the lazy dog"; fulltext += *text; fulltext += "\n"; delete text; } #ifdef OUTPUT std::cout << fulltext << std::endl; #endif }Version mit char * #include <iostream> #include <malloc.h> #include <string.h> int main(){ long int i; size_t strsize; char *text; char *fulltext=NULL; fulltext = (char *) malloc(1); fulltext[0]='\0'; for (i=0;i<1000;i++){ text = (char *) malloc(50); strcpy(text,"The quick brown fox jumped over the lazy dog"); strsize = strlen(fulltext); strsize += strlen(text); strsize += 2; // for the \n and the \0 fulltext = (char *) realloc(fulltext,strsize); strcat(fulltext,text); strcat(fulltext,"\n"); free(text); } #ifdef OUTPUT std::cout << fulltext << std::endl; #endif free(fulltext); }
Hier zeigt sich, dass die Version mit char* sogar deutlich unterlegen ist. Grund: in std::string ist die Länge des Strings gespeichert. Somit sind keine Aufrufe von strlen() nötig. strlen() hat zur Bestimmung der Stringlänge keine andere Möglichkeit, als vom Anfang des Strings an jedes einzelne Zeichen mit '\0' zu vergleichen bis das Ende gefunden wurde. strcat() muss ebenfalls das Ende des Sourcesrings suchen, bis der Destinationstring angehängt werden kann, ist also ebenfalls langsam. Wären die Längen der Strings (wie in diesem Beispiel) schon im Voraus bekannt, könnte auf strlen() und strcat() verzichtet werden und die neuen Längen jeweils in separaten Variablen gespeichert und/oder berechnet werden. Allerdings würde der Aufwand dazu gross, und der Code unübersichtlich und somit unter Umständen auch unsicher. Codegrösse und SpeicherverbrauchIm folgenden Beispiel sollen 1000 Strings angelegt und nicht mehr freigegeben werden. Wie gross wird dabei das ausführbare Programm? Und wieviel Speicher wird zur Laufzeit angeforderd? Version mit std::string#include <iostream> #include <string> int main(){ long int i; std::string text[1000]; for (i=0;i<1000;i++){ text[i] = "The quick brown fox jumped over the lazy dog"; #ifdef OUTPUT std::cout << text[i] << std::endl; #endif } sleep(1000); }Version mit char * #include <iostream> #include <malloc.h> #include <string.h> int main(){ long int i; char *text[1000]; for (i=0;i<1000;i++){ text[i] = (char *) malloc(45); strncpy(text[i],"The quick brown fox jumped over the lazy dog",44); #ifdef OUTPUT std::cout << text[i] << std::endl; #endif } sleep(1000); }Grössen der gestrippten Binaries ohne Optimierung (g++ -O0) -rwxr-xr-x 1 stefan stefan 5196 2005-05-15 16:08 string -rwxr-xr-x 1 stefan stefan 4680 2005-05-15 16:08 charsternGr&oumml;ssen der gestrippten Binaries mit Optimierung (g++ -Os) -rwxr-xr-x 1 stefan stefan 5052 2005-05-15 16:11 string -rwxr-xr-x 1 stefan stefan 4560 2005-05-15 16:11 charstern Die char* Version wird etwa 10% kleiner. Speicherverbrauch laut ksysguard, gestrippt
FazitMit char* statt std::string kann durchaus etwa 10% Leistung gewonnen und etwas Speicher gespart werden. Allerdings ist der Gewinn gering, der Code wird einiges komplizierter und unsicherer. Zudem besteht die Gefahr, bei unsorgfältigem Gebrauch von strlen() und strcpy() sogar sehr massiv Performance zu verlieren. char * kann nur empfohlen werden, wenn die Längen der Strings von Anfang an bekannt sind und keine komplizierten Operationen mit den Strings durchgeführt werden. std::string ist sehr bequem und sicher zu gebrauchen und braucht im schlimmsten Fall doch nur etwa 10% mehr Ressourcen. In vielen Fällen ist std::string sogar performanter. © 2005 by Stefan Heimers |
Kürzlich geändert
Dieser Server (de) 2024-05-04 18:16:25 Defragmentieren (de) 2023-12-21 12:43:54 Vorverstärker (de) 2023-12-21 12:43:54 Sunday Webserver (de) 2023-12-21 12:43:54 Linker (de) 2023-12-21 12:43:54 Partitionieren (de) 2023-12-21 12:43:54 | |||||||||||||||||||||||||||||||||||||||||||||