array vs vector
-
um es zu belegen:
ich habe den code aus dem AMD64 OPtimierungsguide genommen:
http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/25112.PDFtest.c und test2.c sind die beiden Dateien:
mit "gcc -O2 -S -c test.c"der code der generiert wird ist leicht unterschiedlich. ein diff liefert daher viele unterschiede (alles mov*, add*, mul*) aber:
TS-MacBook-Pro:perftest ts$ cat test2.s | grep mov | wc -l 25 TS-MacBook-Pro:perftest ts$ cat test2.s | grep add | wc -l 15 TS-MacBook-Pro:perftest ts$ cat test2.s | grep mul | wc -l 16 TS-MacBook-Pro:perftest ts$ cat test.s | grep mov | wc -l 25 TS-MacBook-Pro:perftest ts$ cat test.s | grep add | wc -l 15 TS-MacBook-Pro:perftest ts$ cat test.s | grep mul | wc -l 16
und natürlich:
TS-MacBook-Pro:perftest ts$ cat test.s | wc -l 77 TS-MacBook-Pro:perftest ts$ cat test2.s | wc -l 77
also wenn es einen unterschied gibt an dem code, dann kann er nicht messbar sein...
-
Einen Unterschied kann es geben wenn der Compiler einmal die Grösse des Arrays kennt, und ein anderes mal nicht.
Mit einem Zeiger wo beim Übersetzen der entsprechenden Codestelle nicht bekannt ist wie gross der dahinterliegende Speicher ist muss der Compiler unter umständen anders umgehen als mit einem Zeiger von dem der Compiler sehr genau weiss worauf er zeigt. Genauso macht es einen Unterschied ob Aliasing ausgeschlossen werden kann oder nicht.Auch könnte es sein dass der Optimizer je nach verwendeter Syntax unterschiedlichen Code erstellt.
Allgemein kann man aber denke ich keine Aussage machen dies oder jenes sei schneller. Für eine bestimmte Version eines bestimmten Compilers vielleicht, aber allgemein wohl nicht. Und natürlich kann es sein dass der Code der auch CPU X schneller läuft auf CPU Y langsamer läuft.
Alles in allem ist die Diskussion IMO ziemlich überflüssig.
-
Shade Of Mine schrieb:
asmcode schrieb:
Shade Of Mine schrieb:
Skym0sh0 schrieb:
ein normales c array ist schneller
wieso sollte das so sein?
beim zugriff mit [] wars glaub ich eine Operation mehr im Assemblercode
Begruendung?
Hier gabs mal dieses Beispiel. Da kannst du die Begründung selber suchen.
void foo() { LONGLONG g_Frequency, g_CurentCount, g_LastCount; //Frequenz holen if (!QueryPerformanceFrequency((LARGE_INTEGER*)&g_Frequency)) std::cout << "Performance Counter nicht vorhanden" << std::endl; //1. Messung QueryPerformanceCounter((LARGE_INTEGER*)&g_CurentCount); int max=50000; std::vector<int> a(max); for (int i=0; i<=max-2; i++) { int x,Min = i; for (int j=i+1; j<=max-1; j++) if (a[j]<a[Min]) Min = j; x = a[i]; a[i] = a[Min]; a[Min] = x; } //2. Messung QueryPerformanceCounter((LARGE_INTEGER*)&g_LastCount); double dTimeDiff = (((double)(g_LastCount-g_CurentCount))/((double)g_Frequency)); std::cout << "Zeit: " << dTimeDiff << std::endl; } void bar() { LONGLONG g_Frequency, g_CurentCount, g_LastCount; //Frequenz holen if (!QueryPerformanceFrequency((LARGE_INTEGER*)&g_Frequency)) std::cout << "Performance Counter nicht vorhanden" << std::endl; //1. Messung QueryPerformanceCounter((LARGE_INTEGER*)&g_CurentCount); int max=50000; int* a = new int[max]; for (int i=0; i<=max-2; i++) { int x,Min = i; for (int j=i+1; j<=max-1; j++) if (a[j]<a[Min]) Min = j; x = a[i]; a[i] = a[Min]; a[Min] = x; } //2. Messung QueryPerformanceCounter((LARGE_INTEGER*)&g_LastCount); double dTimeDiff = (((double)(g_LastCount-g_CurentCount))/((double)g_Frequency)); std::cout << "Zeit: " << dTimeDiff << std::endl; } int main(int argc, char**argv) { foo(); bar(); }
Zeit: 3.79928
Zeit: 1.03572Und ja im Release Mode.
PS: Zusammen kopierter Code, nicht von mir, also keine Kommentare.
-
@asmcode:
Und ja mit dem ollen checked iterators vom MSVC. Dreh die mal ab.
-
Und ein normales C-Array seh ich in dem Code auch keins.
-
lol 2 sekunden unterschied ich nehm nur noch array und nie wieder vector
-
OMGgg schrieb:
lol 2 sekunden unterschied ich nehm nur noch array und nie wieder vector
Genau. Und am besten nimmst du auch noch C-Strings und wir sind alle zufrieden.
-
@asmcode:
Ich liebe es wenn Halbwissen verwendet wird. Standardmaessig hat vector beim VC++ einen range check dabei, zB sind auch iteratoren standardmaessig langsamer da jeder iterator einen next zeiger auf einen anderen iterator hat und bei jedem invalidate von iteratoren (bei vector zB einem reallocate) oder auch wenn der container zerstoert wird, gibt es ein notify an alle iteratoren.das kostet performance und es gibt viel streiterei ob man es im release code drinnen haben will. das muss jeder selbst entscheiden:
#define _SECURE_SCL 0
um es abzudrehen.und dann sind array und vector auch exakt gleich schnell. natuerlich muss man mehr als einen durchgang testen, aber das sollte klar sein.
ich habe deinen code genommen und foo und bar jeweils dTimeDiff returnen lassen und dann abwechselnd 30 mal foo und bar gecallt:
30 runs. vec: overall: 36.5086 arr: overall: 36.556 vec: average: 1.21695 arr: average: 1.21853
lustigerweise ist vec in der messung sogar schneller gewesen. aber das ist nichts anderes als ein messfehler, da der generierte code identisch sein muesste.
PS:
es scheint mittlerweile verloren gegangen zu sein. aber frueher war eines der wichtigsten features von c++ das zero cost principle: abstraktion ist gratis.wenn ich ein normales array nehme und es in eine klasse stecke, dann habe ich dadurch keine runtime kosten. wenn ich jetzt aber zB range checking will, dann kostet das natuerlich schon. aber wenn ich das ohne vector machen wuerde, waere es ja auch nicht gratis.
dieses zero cost principle: ich zahle keine performance kosten fuer abstraktion, scheint irgendwo verloren gegangen zu sein - da ich solche threads wie diesen immer wieder lese. finde ich irgendwie schade.
denn das fasziniert mich an c++ eigentlich so: es gibt keine magie. alles liegt klar und deutlich vor einem...
-
Und wie kommt MS auf die dumme Idee bei [] jetzt auch nen range check einzubauen. Ich bin davon ausgegangen, dass der nur bei at() gemacht wird. Steht das nicht im Standard drin, dass das so sein soll?
-
asmcode schrieb:
Und wie kommt MS auf die dumme Idee bei [] jetzt auch nen range check einzubauen. Ich bin davon ausgegangen, dass der nur bei at() gemacht wird. Steht das nicht im Standard drin, dass das so sein soll?
Bei at ist die Prüfung Pflicht, bei [] ist sie erlaubt. Die Lösung über ein Makro halte ich durchaus für akzeptabel, hätte aber besser an einer Stelle stehen sollen wo man sie nicht so leicht übersieht (z.B. ein Schalter in den Projekteinstellungen).
cu André
-
Oder einfach defaultmäßig aus. So ist es ja fast schon so wie ein Compiler der im Releasemodus defaultmäßig nicht optimieren würde.
-
Es macht durchaus Sinn diese Sicherheitsfeatures einzubauen. Standardmaessig sind sie deshalb aktiv, da MS davon ausgeht dass Leute die es wollen ja ausschalten koennen und die Leute die das nicht interessiert, die sind mit den Ueberpruefungen besser dran.
Ob das Sinn macht ist natuerlich Diskussionswuerdig, aber das ist der Status Quo. Warum nicht mal Doku zum eigenen Compiler lesen...? Mich stoerts nicht, da ich es ja abdrehen kann wenn ich es brauche...
-
Ich finde das auch nicht so schlimm. Abgesehen davon ist der Zug abgefahren bezüglich opt-in vs. opt-out.
-
Naja so prickelnd finde ich das von MS nicht. Das hat mir mal nen schönen Fehler eingehandelt. In einer DLL hatte ich mal testweise den Define drinne, die Hauptanwendnung hatte sie nicht. Nun gabs dauernd Laufzeitfehler. Gut, selber Schuld, aber bis man sowas manchmal entdeckt^^ Von daher mag ich dieses rumstellen per define als Compile-Schalter perse nicht. Das ist ja nicht mal als normale Option in den Eigenschaften drinne. Und auf die Laufzeit kann es sioch ja wirklich negativ ausüben, muss natürlich nicht.
bezüglich opt-in vs. opt-out.
Ich steh grad aufm Schlauch^^ Was willst du uns damit sagen?
Warum nicht mal Doku zum eigenen Compiler lesen...?
Wie weit bist du denn in der MSDN voran geschritten? Ist ja nicht gerade wenig
Ich muss sagen, dass der operator[] ne Überprüfung macht, habe ich auch net gewusst. Ich kannte auch nur das, was in meinem STL-Buch steht: nämlich das das at prüft und [] eben nicht! (und für so ein Buch hab ich 30 Euro gelöhnt^^)Aber aufregen bringt ja nix. is halt so. Und deswegen wieder anfangen alles per Hand zu allokieren: sicher nicht!
-
Pellaeon schrieb:
Warum nicht mal Doku zum eigenen Compiler lesen...?
Wie weit bist du denn in der MSDN voran geschritten? Ist ja nicht gerade wenig
Ich glaub der macht den ganzen Tag nix anderes als Dokus, Bücher und Diskussionen zu lesen.
-
Ich sehe den Sinn dieses Range Checks nicht. Der wirft ja nicht mal eine exception. Als release schmiert das Programm einfach ab (Visual C++ 2008).
vector<int> v(10); try { v[10] = 0; } catch(exception &ex) { cout << ex.what(); } catch(...) { }
-
Schutz gegen Hacker?
-
Stefan schrieb:
Ich sehe den Sinn dieses Range Checks nicht. Der wirft ja nicht mal eine exception. Als release schmiert das Programm einfach ab (Visual C++ 2008).
Sei froh! Ohne Rangchecks läuft das Programme einfach durch, ohne das irgendwas passiert (ja, ich weiß undefiniertes Verhalten, bei mir, mit meinem Kompiler, auf meinem Computer, zu eben dieser Uhrzeit, an eben diesem Ort, bei dieser spezifischen Raumtemparatur passiert nichts). Es wäre doch fatal, wenn solche riesigen Programmierfehler sich in keinster Weise bemerkbar machen. Ein kleiner Programmierfehler in der Software fliegt also eventuell erst auf, wenn das Produkt schon beim Kunden ist. Und dann hat man noch das Problem, dass man nicht weiß, wo der Fehler aufgetreten ist.
Selbst, wenn sich eine Range-Überschreitung "nur" in einem Absturz bemerkbar macht, so lässt sich der Ort des Fehlers doch stark einschränken. In jedem größeren Software Projekt werden die Komponenten ja einzeln getestet. Je nach dem welcher Test dann abstürzt, kennt man dann die defekte Komponente.
-
Ja, aber eine Exception wär trotzdem besser...
-
Geht auch: _SCL_SECURE_THROWS.
Gruß
Don06