Welche Methode findet ihr besser um Klassen zu verwalten ?
-
Ich koennte mir das schon vorstellen, denn die Pointer liegen hintereinander im Speicher, die Alive flags hingegen nicht.
Wenn das Alive oft wechselt, waere es evtl. eine Idee sich zu merken bis zu welchem Index die lebenden Gegner sind und wenn einer stirbt/wiederbelebt wird einfach zwei Eintraege im vector zu tauschen.
Andererseits ist bei 20 Elementen solche Optimierung pure Zeitverschwendung, so langsame Rechner gibts heut ja gar nicht mehr.
-
TGGC schrieb:
Ich koennte mir das schon vorstellen, denn die Pointer liegen hintereinander im Speicher, die Alive flags hingegen nicht.
Ich bin mir jetzt nicht ganz sicher aber ich halte die erste Lösung für schneller.
Bei der Anzahl der Gegner müssten doch auch die Alive flags optimal im Speicher liegen, ist immerhin ein Array von Enemies[] und das Alive flag ist ein member von enemies.
Vielleicht passt das Enemies[] Array sogar in eine processor line aber mindestens in eine Cache Line. Ein Pointer würde da nur eine unnötige weitere Indirektion bedeuteten, weil der Content auf den der Speicher zeigt mit größerer Wahrscheinlichkeit nicht im Cache und nicht auf einer Prozessorline liegt.Oder habe ich irgendwo einen Denkfehler?
-
Ruvi schrieb:
TGGC schrieb:
Ich koennte mir das schon vorstellen, denn die Pointer liegen hintereinander im Speicher, die Alive flags hingegen nicht.
Ich bin mir jetzt nicht ganz sicher aber ich halte die erste Lösung für schneller.
Hier wahrscheinlich ja. Aber generell kann diese Form der Datenlokalität in Extremfällen durchaus relevant werden in Hochleistungsanwendungen. Aber dann gibt es viel bessere Wege dies in C++ zu kapseln.
Auf den Designfehler der zweiten Methode, dass die Level-Klasse auf einmal Speicher verwalten muss (und dies auch noch äußerst schlecht implementiert) gehe ich mal nicht näher ein.
-
Ruvi schrieb:
Vielleicht passt das Enemies[] Array sogar in eine processor line aber mindestens in eine Cache Line. Ein Pointer würde da nur eine unnötige weitere Indirektion bedeuteten, weil der Content auf den der Speicher zeigt mit größerer Wahrscheinlichkeit nicht im Cache und nicht auf einer Prozessorline liegt.
Was ist bitte eine Prozessorline, und was meinst du wie gross eine Cache Line ist?
-
hustbaer schrieb:
Ruvi schrieb:
Vielleicht passt das Enemies[] Array sogar in eine processor line aber mindestens in eine Cache Line. Ein Pointer würde da nur eine unnötige weitere Indirektion bedeuteten, weil der Content auf den der Speicher zeigt mit größerer Wahrscheinlichkeit nicht im Cache und nicht auf einer Prozessorline liegt.
Was ist bitte eine Prozessorline, und was meinst du wie gross eine Cache Line ist?
Also nach meinem Verständnis (vielleicht irre ich mich gut möglich) ist eine Cache Line größer als, dass was der Prozessor mit einem Happen verarbeiten kann und deswegen wird die Cache-Line mit offset gejoint und "Prozessor line" wär für mich persönlich die Menge an Daten die der Prozessor in einem Happen verarbeiten kann. Ich glaube das ist die Register size aber ich bin mir da jetzt nicht ganz sicher, so tief stecke ich nicht drinn.
Vielleicht ist das falsch oder ich habe mich falsch ausgedrückt hier mal eine korrigierte Fassung die genereller gehalten ist:
Vielleicht passt das Enemies[] Array sogar in eine cache line aber höchstwahrscheinlich ist es im Cache. Ein Pointer würde da nur eine unnötige weitere Indirektion bedeuteten, weil der Content auf den der Speicher zeigt nicht in einer Cache line liegt und mit größerer Wahrscheinlichkeit nicht im Cache.
-
Hallo! Ihr diskutiert über Optimierung, solange das Programm noch nicht mal da ist. Leute, schreibt doch erst mal das Programm, so wie es soll.
"premature optimization is evil"
Oder:
`Rules of Optimization:Rule 1: Don't do it.
Rule 2 (for experts only): Don't do it yet.
Rule 3: profile before optimizing`
Und zum original Poster: Fang doch erst mal an, den Code richtig zu formatieren. Ich wundere mich, dass hier so viele Leute trotzdem den Code lesen. Ich schaue mir so etwas erst gar nicht an.
-
tntnet schrieb:
Hallo! Ihr diskutiert über Optimierung, solange das Programm noch nicht mal da ist. Leute, schreibt doch erst mal das Programm, so wie es soll.
QFT.
@Ruvi:
Wir wissen weder wie gross eine "Prozessorline" noch ein Cacheline noch eine enemy Klasse beim OP ist und auch nicht wieviel zwischen zwei Durchlaeufen passiert was den Cache wieder leeren kann. Wieviele Objekte von den 20 alive sind, wissen wir auch nicht. Wie soll man da also ausschliessen, das eine Methode der 2 schneller ist?
-
TGGC schrieb:
QFT.
@Ruvi:
Wir wissen weder wie gross eine "Prozessorline" noch ein Cacheline noch eine enemy Klasse beim OP ist und auch nicht wieviel zwischen zwei Durchlaeufen passiert was den Cache wieder leeren kann. Wieviele Objekte von den 20 alive sind, wissen wir auch nicht. Wie soll man da also ausschliessen, das eine Methode der 2 schneller ist?Ganz klar zählt natürlich measure first aber, es gab ein Artikel und 1 Vortrag von Herb Sutter die mich was Pointer in Container/Datenstrukturen angeht ein wenig wachgerüttelt haben und die Quintessenz dessen war, dass "->" in modernen Prozessor Architekturen eine sehr teure Operation ist und man sie nicht ohne Not verwenden sollte.
Der Artikel:
http://gameprogrammingpatterns.com/data-locality.htmlund auch diesem Vortrag von Herb Sutter:
http://channel9.msdn.com/Events/Build/2014/2-661
Zwischen 23,30min und 41,05min.
-
Ruvi schrieb:
Ganz klar zählt natürlich measure first aber, es gab ein Artikel und 1 Vortrag von Herb Sutter die mich was Pointer in Container/Datenstrukturen angeht ein wenig wachgerüttelt haben und die Quintessenz dessen war, dass "->" in modernen Prozessor Architekturen eine sehr teure Operation ist und man sie nicht ohne Not verwenden sollte.
Der Artikel:
http://gameprogrammingpatterns.com/data-locality.htmlund auch diesem Vortrag von Herb Sutter:
http://channel9.msdn.com/Events/Build/2014/2-661
Zwischen 23,30min und 41,05min.Hat der original Poster irgendwas von Performance gesagt? Ist das irgendwie von Bedeutung? Ist die Stelle, die hier angefragt wird Performancekritisch? Wir wissen es nicht. Daher sollte man das so programmieren, dass es lesbar und gut wartbar ist. Und sich auf keinen Fall irgendwelche Gedanken um Performance machen. Schon die Erwähnung von Performance führt die Leute zu leicht zu unnötig unleserlichen Code. Also lass es einfach.
-
Sorry, ich habe lediglich TGGC Frage beantwortet aber ja wir sind zu weit vom Thema abgeschweift.
Back2Topic:
@TE:
Leider hast Du den Rest deiner Architektur nicht näher erläutert aber wie SeppJ schon geschrieben hat gibt es da sicherlich Optimierungspotenzial.Was den Code angeht den ich sehe würde ich wie SeppJ schon geschrieben hat einen STL::Container verwenden, du hast dort eigentlich freie Auswahl.
Ich würde an deiner Stelle auch RAII verwenden (und damit
unique_ptr<Enemy> ptr;) um deinen Speicher zu verwalten.
Es ist seit dem neuen Standard äußerst untypisch native Pointer memory "ownen" zu lassen.
Der Speicher würde in dem Moment freigegeben in dem du das Objekt aus deinem Container löschst und der Destruktor des SmartPointers aufgerufen wird.Ansonsten würde ich persönlich ranged based for oder Schleifen mit Iteratoren - int basierten Schleifen vorziehen.