vector<string> initialisieren.. -> string==/!=string langsamer als strcmp()??
-
Allerdings hat er wohl nun Probleme, den Speicher wieder freizugeben jedenfalls schmeisst er mit nun beim Verlassen der Funktion einen Ausnahmefehler.
Ich probiere es nun erst einmal mit der boost Lösung.
-
Tja, mit der boost Lösung das gleiche Problem.
Nach Verlassen der Funktion ein Ausnahmefehler.
Nur meldet mir der Compiler diesmal, daß er einen nicht-virtuellen Destruktor hat.Gehe ich recht in der Annahme, daß der vector am Ende nicht freigegeben werden kann und deswegen diesen Ausnahmefehler erzeugt?
-
Don Carsto schrieb:
Gehe ich recht in der Annahme, daß der vector am Ende nicht freigegeben werden kann und deswegen diesen Ausnahmefehler erzeugt?
Dies wäre äußerst ungewöhnlich. Zeig mal mehr Code. Das mit dem fehlenden virtuellen Destruktor klingt schon einmal verdächtig. Erbst du etwa von einem STL-Container?
-
Don Carsto schrieb:
Also, so funktioniert es schonmal nicht. LOL (Wäre auch zu einfach gewesen!!)
Mit Raten kommst Du in C++ nicht weit. Die Sprache bietet da so einige Irregularitäten. Das kann man sich nicht alles selbst zusammen reimen.
-
Don Carsto schrieb:
Tja, mit der boost Lösung das gleiche Problem.
Nach Verlassen der Funktion ein Ausnahmefehler.Wahrscheinlich rufst Du irgendwo undefiniertes Verhalten hervor.
Don Carsto schrieb:
Nur meldet mir der Compiler diesmal, daß er einen nicht-virtuellen Destruktor hat.
Wer hat einen nicht-virtuellen Destruktur und warum sollte das hier eine Rolle spielen?
Don Carsto schrieb:
Gehe ich recht in der Annahme, daß der vector am Ende nicht freigegeben werden kann und deswegen diesen Ausnahmefehler erzeugt?
Falsch geraten.
Versuche das Programm zu verkürzen und vereinfachen und damit den Fehler zu isolieren. Oft findet man so schon den Übeltäter. Wenn Du uns ein kurzes, komplettes Programm zeigen kannst, was sich Deiner Meinung nach ähnlich komisch verhält, dann kann man mehr dazu sagen. Betonung liegt auf "kurz" und "komplett".
-
SeppJ schrieb:
Dies wäre äußerst ungewöhnlich. Zeig mal mehr Code. Das mit dem fehlenden virtuellen Destruktor klingt schon einmal verdächtig. Erbst du etwa von einem STL-Container?
Ich habe nun mal das Ganze in eine einfache Consolen Anwendung gepackt. Die Warnungen mit dem non-virtuell-destruktor kommen trotzdem, aber es läuft ohne Ausnahme durch. (Die Warnungen kommen schon,wenn ich nur die boost-include einbinde) Liegt wohl eher an der hohen Warnstufe des Compilers.
Nun habe ich mal den "fehlerhaften" Code komplett gekürzt und schwupps läuft es durch.
Da scheint irgendein anderes böses Objekt die Ausnahme zu erzeugen.Leider ist der Coee so lang und komplex, daß ein posten nicht viel Sinn macht.
Da ich nun weiß, daß es nicht am vector selbst liegt, sondern eher an dem chaotischen Drumherum, werde ich das mal entwirren (Schritt für Schritt ausblenden) und die fehlerhafte Stelle suchen.
Sinn des Ganzen war sowieso zunächst den Code komplett zu Überarbeiten, um unsichere Stellen auszumerzen.
zu krümelkacker: (Post erst während der Erstellung gelesen)
Ja, leider kann ich keinen vereinfachten Code posten, der sich ähnlich verhält.
Und das mit dem Isolieren habe ich gerade in Angriff genommen. Mal sehen.Jedenfalls funktioniert die boost-Lösung und auch die GCC 4.5 mit dem noch nicht freigegebenen C++ Standard auch. Der Übeltäter ist irgendwo anders im Code.

Vielen Dank nochmal für die Unterstützung. Und die Lösung des Problems.
So.. nun gehts ans Fehlersuchen...

Gruß,
DC
-
So, habe die letzten Stunden damit verbracht den Fehler zu suchen.
Es lag an einem zu kleinen char filestring[40];
Dieses wurde wohl etwas zu weit (um 3 Zeichen) überschrieben.
Dadurch wurde die restliche Speicherverwaltung überaus brüchig.
Hatte sich bisher noch nie bemerkbar gemacht, doch seit ich nun auf std::strings und std::vector umgestellt habe, wurden Ausnahmen geschmissen.Eine tickende Zeitbombe....
-
Ich hoffe mal schwer, du hast nun das
char[]-Array durchstd::stringersetzt und nicht nur um 3 Zeichen vergrössert...
Wechsle bei der Gelegenheit am besten alle rohen C-Arrays aus (gegen
std::tr1::array,boost::array, oderstd::array- alles das Gleiche) und ersetze alle Zeiger auf dynamische Arrays durchstd::vector.
-
Ja, bin dabei, den kompletten Code zu überarbeiten.
Das war ja auch Sinn der Übung, daß ich die char Arrays durch std:string ersetzen wollte, a) um zu gucken, ob es dann eine Performance-Erhöhung gibt und b) weil ich std::string sicherer von der Speicherverwaltung halte.
Nebenher wollte ich dann auch gleich alle mehrdimensionalen char Arrays durch vector<string> ersetzen.Habe nun erstmal eine einigermassen lauffähige Version erschaffen, die sich nun genauso verhält wie die Alte, außer, daß es nun 3x-langsamer geworden ist.
Habe aber auch noch nicht den kompletten Code umgebastelt.
Sind noch einge Krücken drinne.
-
Don Carsto schrieb:
Habe nun erstmal eine einigermassen lauffähige Version erschaffen, die sich nun genauso verhält wie die Alte, außer, daß es nun 3x-langsamer geworden ist.
Sollte nicht sein, wenn man richtig umbaut.
Natürlich sollte man schon einige Dinge beachten, damit der Vergleich überhaupt gerechtfertigt ist:
- Ganze Container so selten wie möglich kopieren. Lieber mit Const-Referenzen oder Iteratoren arbeiten.
- Generell Objekt-Kopien vermeiden durch Einsatz von
swap()und Move-Semantik in C++0x. - Wenn die Grösse bei
std::vectorundstd::stringim Voraus bekannt ist, mitreserve()vorallokieren. - Im Release-Modus kompilieren und Debug-Laufzeitumgebung abschalten.
- Sicherheitsmassnahmen wie Checked-Iterators deaktivieren.
-
So, habe nun die Bremse gefunden.
Sehr kurios.Hatte zunächst nach dem Umstellen auf string und vector folgendes sehr zeitaufwendige Konstrukt von char-Array auf string umgestellt (Dieses wird etwa 26000 mal aufgerufen)
(Die Schleife selbst ->for(int aa=0;aa<shad_sku.size();aa++)<- ca.65000 mal)Hier das Original mit char-Array:
if (teilupdate==1) { if (strcmp(test[spalmengel],"0")==0) strcpy(app,"x"); strcpy(bigbuffer,""); sprintf(bigbuffer,"%s\t%s\t%s\t%s\t%s\t%s\t%s\t\t\t%s\t%s\t%s\t%s\t%s\t\t\t\t%s\t%s\t%d\t\n",test[spalsku],test[spalautor] ,fattitle,test[spalverlag],test[spaljahr],test[spalformat],test[spalpreis],test[spalmengel],test[spalamazustand],fatnote,test[spalkatamazon],test[spalsprache],amaurl,app,7); for (int aa=0;aa<anzsku;aa++) { if (strcmp(shad[aa].sku,test[spalsku])==0) { if((strcmp(shad[aa].anz,test[spalmengel])!=0)||(strcmp(shad[aa].dat,test[spalaenderung])!=0)) {f << bigbuffer;aa=anzsku;flag=1;NR++;} else {aa=anzsku;flag=1;} } } if (flag==0) {f << bigbuffer;NR++;} rectx=SUMAKT*balkx/SUMMAX;SUMAKT++; }Laufzeit flotte 16 Sekunden.
Dann die Abänderung ins std::string + vector:
bigbuffer ist nun ein stringstream, aber der bremst nicht.if (teilupdate==1) { if (test[spalmengel]=="0") strcpy(app,"x"); bigbuffer << test[spalsku] << "\t" << test[spalautor] << "\t" << fattitle << "\t" << test[spalverlag] << "\t" << test[spaljahr] << "\t" << test[spalformat] << "\t" << test[spalpreis] << "\t\t\t" << test[spalmengel] << "\t" << test[spalamazustand] << "\t" << fatnote << "\t" << test[spalkatamazon] << "\t" << test[spalsprache] << "\t\t\t\t" << amaurl << "\t" << app << "\t" << "7" << "\t\n"; for (int aa=0;aa<shad_sku.size();aa++) { if (shad_sku.at(aa)==test[spalsku]) { if((shad_anz.at(aa)!=test[spalmengel])||(shad_dat.at(aa)!=test[spalaenderung])) { f << bigbuffer.str(); flag=1; NR++; break; } else { flag=1; break; } } } if (flag==0) {f << bigbuffer.str();NR++;} rectx=SUMAKT*balkx/SUMMAX;SUMAKT++; }Laufzeit grobe 60 Sekunden.
Dann nun wieder abgeändert in:
if (teilupdate==1) { if (strcmp(test[spalmengel].c_str(),"0")==0) strcpy(app,"x"); bigbuffer << test[spalsku] << "\t" << test[spalautor] << "\t" << fattitle << "\t" << test[spalverlag] << "\t" << test[spaljahr] << "\t" << test[spalformat] << "\t" << test[spalpreis] << "\t\t\t" << test[spalmengel] << "\t" << test[spalamazustand] << "\t" << fatnote << "\t" << test[spalkatamazon] << "\t" << test[spalsprache] << "\t\t\t\t" << amaurl << "\t" << app << "\t" << "7" << "\t\n"; for (int aa=0;aa<shad_sku.size();aa++) { if (strcmp(shad_sku.at(aa).c_str(),test[spalsku].c_str())==0) { if((strcmp(shad_anz.at(aa).c_str(),test[spalmengel].c_str())!=0)||(strcmp(shad_dat.at(aa).c_str(),test[spalaenderung].c_str())!=0)) { f << bigbuffer.str(); flag=1; NR++; break; } else { flag=1; break; } } } if (flag==0) {f << bigbuffer.str();NR++;} rectx=SUMAKT*balkx/SUMMAX;SUMAKT++; }Also sämtliche string==string und string!=string Vergleiche durch strcmp(x,y)==0/!=0 ersetzt.
Laufzeit grobe 25 Sekunden..at() und .size() Verzicht führt zu keinerlei Veränderung.
Warum ist string==string string!=string langsamer als strcmp() ??
Gibt es da eine Abhilfe?
Gruß,
DC
-
Und welche Compileroptionen? Keine Ahnung was f ist und sonst bleibt auch nur raten uebrig.
.at() und .size() Verzicht führt zu keinerlei Veränderung
Na das wuerde mich stutzig machen.
Warum ist string==string string!=string langsamer als strcmp()?
Hmm, es ist nicht langsamer. Anstatt zu raten, benutze einen Profiler!
-
Hast du meine Ratschläge befolgt (besonders die letzten beiden)?
Ansonsten kann ich mich knivil anschliessen. Und benutze bitte [cpp]- statt [code]-Tags, die haben Syntaxhighlighting.
-
Nexus schrieb:
Hast du meine Ratschläge befolgt (besonders die letzten beiden)?
Ja, habe etliche Kombinationen probiert und es führte zun Nichts.
Vorallokierung mit .reserve() gab auch keinelei Vorteile.Ansonsten kann ich mich knivil anschliessen. Und benutze bitte [cpp]- statt [code]-Tags, die haben Syntaxhighlighting.
[quote]
Okay, habe nun nochmals den Schleifenkörper auf Durchläufe geprüft und muss sagen es sind insgesamt: 2075966830 Durchläufe. !!Jaja, was für ein Wahnsinn!!
(Es werden hier zwei Tabellen miteinander verglichen. Die 1.Tabelle hat knappe 65000 Einträge die 2.Tabelle ca.26000.)Da beide Tabellen aber nach gleichem Kriterium sortiert sind, muß ich garnicht jedesmal die komplette Tabelle nach einem Match durchsuchen, sondern es reicht, wenn ich nach einem Fund, einfach den Schleifenstartindex hochsetze.
(Dadurch verkleinert sich der Suchbereich)
Nachdem ich diese kleine Korrektur vorgenommen hatte, sind es nur noch 64435 Durchläufe.
Auf dieser Basis habe ich nun die strcmp's wieder durch string==string ersetzt und die Zeit ist nun ohne merkliche Unterschiede jedesmal knappe 8 Sekunden.(Hatte auch gestern mal eine Lösung mit <vector>.erase() versucht, aber durch diese dynamische Vectorverkleinerung schrumpfte zwar der Suchbereich, aber es dauerte auch sehr lange, weil das Entfernen eines Vector-Elements wohl auch recht zeitaufwendig ist)
Auf jeden Fall spielt wohl die Anzahl der Schleifen eine Rolle.
Wenn ich nun richtig gerechnet habe ist der Unterschied zwischen strcmp und string==string 0,000000025 Sekunden.
Bei 65000 Durchläufen wären es 0,0016 Sekunden länger.
Und bei 2000000000 Durchläufen schon 50 Sekunden.Gruß,
DC
-
Don Carsto schrieb:
Nexus schrieb:
Hast du meine Ratschläge befolgt (besonders die letzten beiden)?
Ja, habe etliche Kombinationen probiert und es führte zun Nichts.
Vorallokierung mit .reserve() gab auch keinelei Vorteile.Das deckt sich nicht mit deiner anderen Aussage, dass der Verzicht auf at() nichts bringt. Wenn du tatsächlich eine auf Laufzeit optimierte Version von vector benutzt, dann muss dies einen gewaltigen Unterschied machen.
Das klingt so, als wüsstest du deinen Compiler nicht richtig zu bedienen.
-
Okay, mag sein, da fehlt mir auch die Erfahrung. Habe umgestellt von DevC++ mit MinGW 3.xx auf CodeBlocks mit MinGW 4.5.
Da gibt es bei Compileroptionen verschiedene Optimierungsarten für Geschwindigkeit, Größe und Expensive.
Hatte da verschiedene Kombinationen ausprobiert.
Debuggersymbole erzeugen hatte ich auch ausgeschaltet usw.Wie gesagt, meine Compilierugnen mit oder ohne .at() ergab keine signifikanten Geschwindigkeitsvorteile.
Gut, Vielleicht hat CodeBlocks noch nicht alle von MinGW unterstützten Optimierungsarten in seinem Häkchenmenü. Da müßte ich die dann eventuell mal als Zusatzoption einstellen.
Werde mich mal doch näher mit der Anleitung von MinGW beschäftigen.
-
Dass .at() vs. [] keinen (messbaren) Unterschied macht wundert mich nicht.
Mich wundert eher, dass bei strcmp() vs. string == string die strcmp() Variante schneller sein soll.
Wenn überhaupt ein Unterschied ist, dann müsste string == string schneller sein, da es z.B. bei unterschiedlicher Länge sofort "false" melden kann, wohingegen strcmp noch entscheiden muss ob "1" oder "-1" (also welcher String "vor" dem anderen kommt).
Hast du diesen Unterschied, also strcmp vs. operator ==, auch in einem "Release Build" (=volle Optimierungen) getestet? Oder war das vielleicht mit einem "Debug Build"?
Bei einem Debug-Build kann ich mir das nämlich leicht vorstellen, da strcmp() meist gut optimierter C-Code ist, der auch ohne Optimierungen einigermassen schnell läuft ... wohingegen operator == für Strings oft nicht so gut optimiert ist. Bzw. es können da Dinge wie Debug-Iteratoren reinpfuschen.
-
std::vector<std::string> sprache({"deu", "eng"});sollte btw auch funktionieren.
-
Ja, habe sämtliche Optimierungen aktiviert, Debugmodus deaktiviert.
Aber wie schon gesagt, der Unterschied zwischen strcmp() und str==str betrug nur 0,000000025 Sekunden pro Schleifendurchlauf.
Was sich dann bei 2075966830 Schleifendurchläufen als 50 Sekunden manifestierte.
Jetzt, wo es nur noch knappe 64000 Durchläufe sind, hat es sich relativiert.Dann habe ich heute auch mal den Code auf Iteratoren umgestellt, aber das ergab auch nicht die dollen sichtbaren Unterschiede. Ob nun 8,5 oder 8,2 oder 8,8 Sekunden ist eingentlich egal, es ging eher um den Unterschied von 16 Sekunden zu 60 Sekunden.
Mal sehen, vielleicht entdecke ich ja bei weiteren Forschungen doch noch einen Beschleuniger. Vielleicht einen anderen Containertyp ausprobieren usw.Gruß,
DC
-
Don Carsto schrieb:
Aber wie schon gesagt, der Unterschied zwischen strcmp() und str==str betrug nur 0,000000025 Sekunden pro Schleifendurchlauf.
Was sich dann bei 2075966830 Schleifendurchläufen als 50 Sekunden manifestierte.(...)
ging eher um den Unterschied von 16 Sekunden zu 60 Sekunden.
Ich würde 44 von 60 Sekunden schon viel nennen.
Wenn du andrer Meinung bist, dann überweis' mir einfach monatlich 73% deines Gehalts