Unangenehmes Problem mit sprintf_s


  • Administrator

    Ishildur schrieb:

    die z.B. bei MSVC++ auch im Releasemodus explizit deaktiviert werden müssen

    Hoppla, ja da hatte ich tatsächlich nichts entsprechendes deaktiviert, wie mache ich denn das?

    http://msdn.microsoft.com/en-us/library/aa985965.aspx

    Ishildur schrieb:

    Da bin ich anderer Meinung. Auf die 60Hz kommt man IMHO durch das V-Sync (Das man IMHO ruhig ausschalten kann, da Flachbildschirme ohnehin keinen Ionenestrahl mehr haben der Zeile für Zeile die Phosphorteilchen zum leuchten bringt)

    Das ist völliger Humbug. VSync ist bei LCD immer noch nötig. Wenn die Graphikkarte mit höherer Geschwindigkeit Bilder produziert als der Bildschirm Herz hat, dann kann es immernoch zu Überlappungen kommen, weil womöglich zu dem Zeitpunkt, als sich der Bildschirm sein Bild holte, die Graphikkarte gerade in den Puffer am schreiben war.

    Ishildur schrieb:

    Der Punkt dabei war einfach, dass ich für die Textengine (1000fps, was du mir ja nicht glaubst) ein deferred Rendering verwende. Sprich, wenn ich SpriteBatch::DrawText aufrufe, wird noch gar nichts gezeichnet, sondern der entsprechende Text als DrawJob gespeichert. Schliesslich wird einmal pro Frame der komplette Text mit Hilfe eines einzigen Rendercalls gerendert. Dafür muss aber nach jedem Frame der std::vector der Drawjobs komplett entleert werden. Mit einem nativen c - array war dieser Enleerungsprozess jedoch hinfällig, weil ich stattdessen die DrawJobs da lasse wo sie sind und stattdessen eifach den Zeiger wieder auf das erste Element setze, so werden die alten Drawjobs nach und nach überschrieben. (Was eigentlich jedes Betriebssystem auch so macht, wird ja auch nicht jedes bit mit null überschrieben, wenn eine Datei gelöscht wird...)

    Also das musst du mir jetzt nochmals genauer erklären. Wieso müsste eigentlich ein std::vector entleert werden, ein C Array aber nicht? Wer zwingt dich überhaupt clear aufzurufen? Abgesehen davon, dass natürlich ein clear eigentlich gar keinen Speicher freigeben würde. Das klingt für mich, dass du std::vector regelmässig gelöscht und neu Speicher reservieren hast lassen und dich dann darüber wunderst, wenn du dies mit einem C Array nicht machst, dass es schneller ist.

    Da bekommt man doch etwas Zweifel an deinen Performance-Messungen 😉

    Ishildur schrieb:

    oder strings aus einem statischen memory pool aufbauen

    Genau das mache ich doch??

    Nein, du verwendest schlicht und einfach C Strings mit einem Memory Pool. Dabei gäbe es Möglichkeiten sowas zu kapseln. Man könnte zum Beispiel einen Memory Pool erstellen und die std::string von dort ihren Speicher holen lassen. Oder man erstellt Views auf den Speicher mit eigenen Klassen. Es gäbe verdammt viele Möglichkeiten sowas zu optimieren und zwar auch direkt mit der STL.

    Es gäbe zum Beispiel auch die Möglichkeiten den Allocator zu ändern oder man kann sich Klassen bauen, welche automatisch Speicher aus einem Memory Pool besorgen, wenn einem die Allocators zu unangenehm sind.

    Ein Stichwort wäre hier zum Beispiel: Small Object Allocator.
    Eine mögliche Implementation hat Andrei Alexandrescu in seinem Buch Modern C++ Design vorgestellt. Der Code ist im Internet in der Loki Bibliothek vorhanden:
    http://loki-lib.sourceforge.net/
    http://loki-lib.cvs.sourceforge.net/loki-lib/loki/include/loki/SmallObj.h?view=markup

    Daran sieht man, was für Möglichkeiten einem offen stehen und man kann das für seine Zwecke verändern.

    Genau das mache ich doch?? Ich finde C++ super, nur viele der Standardbibliotheken passen mir nicht und habe ich desshalb durch eigene Implementationen ersetzt.

    Das sieht aber nicht wirklich danach aus. Es sieht mehr nach einem C mit Klassen aus. Schon nur deine C Strings deuten darauf hin, welche du nicht sinnvoll gekapselt hast. Wahrscheinlich auch an vielen Orten Dinge wie RAII missachtet, usw. usf.
    Es sieht hauptsächlich danach aus, als wenn du die C++ Standardbibliothek weggeworfen hast und nun die C Bibliothek einsetzt und dies einfach in Klassen. Das ist aber kein sinnvoller und sicherer Ersatz.

    Für eine Korrektur ist es sicherlich zu spät, da stimme ich dir zu. Nur solltest du vielleicht aufpassen, was du in die Arbeit schreibst, wieso du so programmiert hast. Und für die Zukunft gibt es noch einiges zu lernen 🙂

    Grüssli



  • Ishildur schrieb:

    Ich benutze den QueryPerformanceCounter also nix 1ms Raster :p

    Ok. Kannst du mal den Code zeigen, der aus der gemessenen Zeit die Frequenz für die Anzeige berechnet?

    Ishildur schrieb:

    Außerdem stellt sich die Frage, wie relevant diese Messung ist, weil für ein Spiel weder 500 Hz noch 1000 Hz vernünftig sind. Ein Spiel läuft heutzutage in der Regel mit 60 FPS

    Da bin ich anderer Meinung. Auf die 60Hz kommt man IMHO durch das V-Sync (Das man IMHO ruhig ausschalten kann, da Flachbildschirme ohnehin keinen Ionenestrahl mehr haben der Zeile für Zeile die Phosphorteilchen zum leuchten bringt) 60Hz ist für das Auge durchaus vernünftig und völlig ausreichend, nicht jedoch für die Haptik, da wärend 1kHz und mehr durchaus wünschenswert...

    Zu dem was Dravere dazu geschrieben hat möchte ich noch hinzufügen, dass ich den Sinn von Optimierungen fragwürdig finde, die dazu dienen, die Anzahl der berechneten, aber letztlich sowieso unsichtbaren Bilder von 440 auf 940 zu steigern 🙂

    Und die Sache mit der Haptik... 1000 Hz liegt mit Sicherheit weit jenseits der Abfragefrequenz von so ziemlich jedem Eingabegerät. Es würde mich wundern, wenn irgendein Gerät öfter als vielleicht 100x pro Sekunde abgefragt würde.



  • Das ist völliger Humbug. VSync ist bei LCD immer noch nötig.

    Ja meinetwegen, ich habe zusammen mit meinem Partner 5 Testgeräte, das Spiel hat überall unterschiedliche Frameraten, ein Flackern oder sonstige typische Effekte von ausgeschaltetem V-Sync konnten wir nirgends wahrnehmen, sollte sich dies ändern hat der Spieler jederzeig die Möglichkeit, V-Sync einzuschalten.

    Wer zwingt dich überhaupt clear aufzurufen?

    Kannst du mir jetzt mal erklären, wieso DU uuuuuuunbedingt einen std::vector benutzen willst (und mich als völligen Idiot hinstellst, weil ich es nicht tue) wenn du die von der std::vector Klasse gegenüber einem nativen array erweiterte Funktionalität überhaupt nicht benutzt?

    ein, du verwendest schlicht und einfach C Strings mit einem Memory Pool. Dabei gäbe es Möglichkeiten sowas zu kapseln. Man könnte zum Beispiel einen Memory Pool erstellen und die std::string von dort ihren Speicher holen lassen. Oder man erstellt Views auf den Speicher mit eigenen Klassen. Es gäbe verdammt viele Möglichkeiten sowas zu optimieren und zwar auch direkt mit der STL.

    Ja da gebe ich dir völlig recht, das hätte man durchaus tun können. Angesichts der knappen Zeit habe ich aber die in meinen Augen deutlich weniger aufwändige Alternative mit C-Strings für die wenigen Stellen, an der dies notwenig ist bevorzugt, anstatt ein komplettes Framework zu schreiben, welches schliessch an 1, 2 Stellen im Programm benutzt wird.

    Und für die Zukunft gibt es noch einiges zu lernen
    

    Wer kann das nicht von sich behaupten? :p


  • Administrator

    Ishildur schrieb:

    Wer zwingt dich überhaupt clear aufzurufen?

    Kannst du mir jetzt mal erklären, wieso DU uuuuuuunbedingt einen std::vector benutzen willst (und mich als völligen Idiot hinstellst, weil ich es nicht tue) wenn du die von der std::vector Klasse gegenüber einem nativen array erweiterte Funktionalität überhaupt nicht benutzt?

    1. Ich will dich nicht als völligen Idioten hinstellen. Ich will dir nur mögliche Fehler aufzeigen, da man aus Fehlern lernt.
    2. Du willst mir doch nicht sagen, dass std::vector::clear aus deiner Sicht die einzige andere Funktionalität zu einem C Array darstellt?
    Zudem gäbe es, wie ich schon früher mal sagte, die Möglichkeit von std::tr1::array , bzw. boost::array , falls du statische Arraygrössen hast.

    Ishildur schrieb:

    Ja da gebe ich dir völlig recht, das hätte man durchaus tun können. Angesichts der knappen Zeit habe ich aber die in meinen Augen deutlich weniger aufwändige Alternative mit C-Strings für die wenigen Stellen, an der dies notwenig ist bevorzugt, anstatt ein komplettes Framework zu schreiben, welches schliessch an 1, 2 Stellen im Programm benutzt wird.

    Ich zweifle sehr stark daran, dass dies der weniger aufwendigere Weg gewesen ist. Auf den ersten Blick mag dies vielleicht stimmen, aber spätestens beim Zweiten solltest du erkennen, wie fehleranfällig solche C Konstrukte sein können. Vielleicht hast du ein bisschen weniger Aufwand zum Schreiben (wobei ich sogar dies bezweifle), dafür kannst du dir eine Menge Ärger zu einem späteren Zeitpunkt einholen. Dass du ein komplettes Framework dafür schreiben müsstest, ist theatralisch übertrieben.

    Auch finde ich es irgendwie lustig, dass du auf die C++ Möglichkeiten verzichtest, C einsetzt, dann aus Sicherheitsgründen auf nicht standardisierte Funktionen wie sprintf_s setzt und am Ende damit noch in undefiniertes Verhalten reinrennst 😉

    Ishildur schrieb:

    Und für die Zukunft gibt es noch einiges zu lernen
    

    Wer kann das nicht von sich behaupten? :p

    Ich natürlich ... zweifelst du das in etwa an? 🤡
    Es war aber mehr im Sinne gemeint, dass du aus deinen Ergebnissen besser nicht all zu viele Schlüsse für die Zukunft in der Programmierung in C++ ziehen solltest. Du dich daher besser zu der Thematik mit zum Beispiel Fachliteratur informieren solltest.

    Grüssli



  • Ishildur schrieb:

    Kannst du mir jetzt mal erklären, wieso DU uuuuuuunbedingt einen std::vector benutzen willst (und mich als völligen Idiot hinstellst, weil ich es nicht tue) wenn du die von der std::vector Klasse gegenüber einem nativen array erweiterte Funktionalität überhaupt nicht benutzt?

    Weil deine Argumentation falsch ist. ob vector oder nicht, so eine funktionalität hat gekapselt zu sein. und deine argumentation mit allokationen ist ebenfalls falsch - denn es ist nicht notwendig hier allokationen zu haben, auch vector macht keine.

    nur vector oder etwas entsprechendes würde hier eine menge code sparen. was wenn du plötzlich mehr draw jobs hast?

    Ja da gebe ich dir völlig recht, das hätte man durchaus tun können. Angesichts der knappen Zeit habe ich aber die in meinen Augen deutlich weniger aufwändige Alternative mit C-Strings für die wenigen Stellen, an der dies notwenig ist bevorzugt, anstatt ein komplettes Framework zu schreiben, welches schliessch an 1, 2 Stellen im Programm benutzt wird.

    eine klasse oder ein allokator, der aufwand sind vielleicht 30min.
    ne ne, das zählt nicht.

    deine entscheidungen mögen ja vielleicht sinn machen - aber deine argumentation ist falsch.



  • @Nukularfüsiker

    Ok. Kannst du mal den Code zeigen, der aus der gemessenen Zeit die Frequenz für die Anzeige berechnet?

    Besser nicht sonst werde ich hier noch mehr zusammengestaucht :p

    Zu dem was Dravere dazu geschrieben hat möchte ich noch hinzufügen, dass ich den Sinn von Optimierungen fragwürdig finde, die dazu dienen, die Anzahl der berechneten, aber letztlich sowieso unsichtbaren Bilder von 440 auf 940 zu steigern 🙂

    Naja, wenn ich sämtliche Komponenten zusammenfüge inklusive Physik und AI bin ich schon bei unter 100 fps, aber für die Performance Tests der einzelnen Komponenten schalte ich alle anderen zwischenzeitlich aus. Die Textengine arbeitet (wenn alles andere deaktiviert ist) mit den 1000 fps, aber auch nur dann, wenn ich nur eine enzige Schrift verwende. Muss ich während dem Rendern noch ein Texturwechsel vornehmen, sinkt die Framerate auch gleich wieder drastisch, weil ich es dann in zwei Render Calls aufteilen muss, wobei ich natürlich nach Textur gruppiere.

    1000 Hz liegt mit Sicherheit weit jenseits der Abfragefrequenz von so ziemlich jedem Eingabegerät

    Ich studiere den Schwerpunkt "Computer Perception & Virtual Reality" offenbar sind dann alle unsere Scripts fehlerhaft... :p
    Gucks du hier: http://www.pc-cooling.de/Eingabegeraete/Maeuse/900500200/SPEEDLINK+Kudos+Gaming+Mouse,+black.html

    @Dravere

    Auch finde ich es irgendwie lustig, dass du auf die C++ Möglichkeiten verzichtest, C einsetzt, dann aus Sicherheitsgründen auf nicht standardisierte Funktionen wie sprintf_s setzt und am Ende damit noch in undefiniertes Verhalten reinrennst

    Jaja, das findest du jetzt lustig was du Assi :p



  • Ishildur schrieb:

    @Nukularfüsiker

    Ok. Kannst du mal den Code zeigen, der aus der gemessenen Zeit die Frequenz für die Anzeige berechnet?

    Besser nicht sonst werde ich hier noch mehr zusammengestaucht :p

    Dann vielleicht als genereller Tipp: Zeig zusätzlich zu den FPS auch die Framedauer in ms an, bis auf 2 Stellen hinter dem Komma (sollte mit PerformanceCounter ja kein Problem sein) und benutze diese Zahl für Vergleiche. FPS sind irreführend, weil bei 1000 FPS beispielsweise 0.5 ms Mehraufwand als dramatischer Verlust von 333 FPS dargestellt werden. Bei 60 FPS wären das gerade mal 2 Frames weniger. Und Rundungsfehler bei der Umrechnung können auch eine erhebliche Abweichung verursachen.

    1000 Hz liegt mit Sicherheit weit jenseits der Abfragefrequenz von so ziemlich jedem Eingabegerät

    Ich studiere den Schwerpunkt "Computer Perception & Virtual Reality" offenbar sind dann alle unsere Scripts fehlerhaft... :p
    Gucks du hier: http://www.pc-cooling.de/Eingabegeraete/Maeuse/900500200/SPEEDLINK+Kudos+Gaming+Mouse,+black.html

    Ok, ich erkenne die Existenz dieser "Gaming Mouse" an, die 1000 Hz polling rate verspricht. Was diese Werbeaussauge in der Realität wert ist, kann ich nicht beurteilen. Und übliches Equipment dürfte erheblich langsamer abgefragt werden.



  • @Shade of Mine
    denn es ist nicht notwendig hier allokationen zu haben, auch vector macht keine.

    std::vector<int> lsInt;
     int index = 0;
    
    int aInt[MAX_TEXT];
     int index = 0;
    

    Wo ist jetzt der Unterschied? Das std::vector selbstständig wächst? Ja aber nicht wenn ich den [] operator von std::vector benutze um daraum zuzugreifen. Damit std::vector wächst muss ich Add benutzen. Und wenn ich Add benutze muss ich doch auch Clear benutzten?? Natürlich, im einfachsten Fall setzt Clear einfach den internen AddZeiger wieder auf 0, aber eben man weiss nicht so genau was das Ding dann wirklich macht? Bei einem nativen array weiss ich hingegen genau was ich mache. Zusätzlich wird einfach von Vector jedes Mal, wenn ich diese Methode aufrufe ein new und ein delete erzeugt. Während das native Array einfach ein sub esp MAX_TEXT macht? Was wird wohl schneller sein?

    eine klasse oder ein allokator, der aufwand sind vielleicht 30min.

    Ein Memorypool Manager, der sämtliche Instancen informieren muss, wenn eine Reallokation auf dem Heap stattgefunden hat programmierst du in 30min? 😮



  • @Nukularfüsiker

    Dann vielleicht als genereller Tipp: Zeig zusätzlich zu den FPS auch die Framedauer in ms an

    Das überzeugt mich! Eine Sekunde bin gerade dabei 🙂

    Und übliches Equipment dürfte erheblich langsamer abgefragt werden.

    Ich sagte auch bloss dass 1kHz und mehr wünschenswert wären. Das Problem ist einfach die menschliche Sensorik. Das Auge ist einfach ein extrem träger biometrischer Sensor. Der Tastsinn bspw. reagiert einfach extrem viel schneller und sensibler. Man merkt dies bspw. schon an einfachen Games. Bei 30 fps reagiert bspw. die Steuerung bereits extrem träge obwohl das Bild noch nicht ruckelt. Für das Auge ist es noch schnell genug, aber all unsere anderen Sensoren bemerken längst, dass da etwas nicht stimmt...



  • Ishildur schrieb:

    Wo ist jetzt der Unterschied?

    MAX_TEXT

    das ist der einzige.

    dh, du sparst speicher mit vector 😉

    und natürlich die sicherheit mit bounds checking und so, das was man in c++ hat alles gratis bekommt.

    Ein Memorypool Manager, der sämtliche Instancen informieren muss, wenn eine Reallokation auf dem Heap stattgefunden hat programmierst du in 30min? 😮

    klar.
    voraussetzung ist halt, dass der code schon existiert. oder wie hast du ihn in C geschrieben? da ein c++ interface drumherum um eben bufferoverlows und co zu verhinden dauert dann 30min.

    PS:
    rendering und input verarbeitung tust du aber schon trennen, oder?
    FPS sind ein komplett uninteressantes mess werkzeug. denn du willst zwar viele frames haben, aber über 60 ist es irrelevant wieviele mehr es sind.

    input und logik läuft davon sowieso getrennt.



  • Ishildur schrieb:

    denn es ist nicht notwendig hier allokationen zu haben, auch vector macht keine.
    ...
    Wo ist jetzt der Unterschied? Das std::vector selbstständig wächst? Ja aber nicht wenn ich den [] operator von std::vector benutze um daraum zuzugreifen. Damit std::vector wächst muss ich Add benutzen. Und wenn ich Add benutze muss ich doch auch Clear benutzten??...

    Mal ganz davon abgesehen das std::vector weder eine Add noch eine Clear-Methode hat (wenn schon push_back und clear), und clear nicht nötig ist, wenn du ihn nur überschreiben willst, kann man einem vector auch für eine feste Größe reservieren lassen (Denn ansonsten kann ggf. beim push_back ein umkopieren nötig werden => was sich tatsächlich in der Performance unterscheidet).

    Wenn man std::vector RICHTIG verwendet (sprich in deinem Fall auch mit reserve oder resize, bzw. richtigen Konstruktor um die Größen festzulegen, oder den Speicher richtig zu reservieren), ist er kaum mehr von einen C-Array zu unterscheiden. Hierfür gibt es auch noch einen besseren Ersatz: std::tr1::array oder boost::array.

    Ishildur schrieb:

    Zusätzlich wird einfach von Vector jedes Mal, wenn ich diese Methode aufrufe ein new und ein delete erzeugt.

    Das ist schlicht und ergreifend falsch. Ein vector allokiert zwar Speicher, diesen aber an einen Stück und auch für mehrere Elementen. Ein push_back führt nur dann zu einem neuallokieren, wenn der reservierte Speicher nicht ausreicht. Ein Vector der richtig initialisiert wurde (sprich wenn man die richtige Größe auch weiß), wird nicht einmal den Speicher neu reservieren.

    // Eine der nachfolgenden Zeilen einfach austauschen...
    int v[10];
    // std::vector<int> v(10, 0);
    // std::tr1::array<int, 10> v;
    
    for(int i=0; i<10; ++i)
      v[i] = i;
    

    So schon hast du die Array-Notation. Die array-Klasse ist dabei imho die beste Wahl wenn die Größe bekannt ist (Da man sie auch bei Bedarf einfach kopieren kann usw.), und gegenüber einen C-Array so gut wie keinen Overhead besitzt.



  • @Shade Of Mine

    rendering und input verarbeitung tust du aber schon trennen, oder?

    Wie meinst du das genau?

    aber über 60 ist es irrelevant wieviele mehr es sind.

    WOW, ist das dein Ernst? Also wenn das Spiel bei meinem Super Highend PC mit über 60fps läuft, muss ich nichts mehr optimieren? Selber Schuld wenn die potentiellen Käufer halt keinen so tollen PC haben? :p

    @asc

    Das ist schlicht und ergreifend falsch. Ein vector allokiert zwar Speicher, diesen aber an einen Stück und auch für mehrere Elementen

    Ja schon, aber eben jedesmal wenn dieser std::vector erzeugt wird 😉

    // Eine der nachfolgenden Zeilen einfach austauschen...
    int v[10];                       // sub esp 0ah
    // std::vector<int> v(10, 0);    // hier ist intern IMHO ein new erforderlich, da die Grösse zur Compilezeit nicht bekannt ist.
    // std::tr1::array<int, 10> v;   // OK, hier ist grösse bekannt, clever! :) 
    
    for(int i=0; i<10; ++i)
      v[i] = i;
    

    Ist dieser Code in einer Funktion, die 10 mal pro Frame aufgerufen wird bei 500 fps verursacht std::vector 5'000 Memoryallokationen pro Sekunde, dass sind bei einer Programmdauer von 2 Spielstunden 180 Mio. Allokationen mehr als nötig. Verursacht durch ein einziges std::vector. std::tr1::array muss ich noch genau anschauen, was das genau macht, bevor ich etwas dazu sagen kann...



  • Ishildur schrieb:

    @Shade Of Mine

    rendering und input verarbeitung tust du aber schon trennen, oder?

    Wie meinst du das genau?

    Du renderst unabhängig von der logik und dem input. Logik muss man vom Rendering ja sowieso trennen, da du in einem logik-tick ja je nach hardware leistung unterschiedlich viele frames berechnen kannst.

    aber über 60 ist es irrelevant wieviele mehr es sind.

    WOW, ist das dein Ernst? Also wenn das Spiel bei meinem Super Highend PC mit über 60fps läuft, muss ich nichts mehr optimieren? Selber Schuld wenn die potentiellen Käufer halt keinen so tollen PC haben? :p

    bewegen wir uns echt auf so einem niveau?

    Ja schon, aber eben jedesmal wenn dieser std::vector erzeugt wird 😉
    [...]Ist dieser Code in einer Funktion, die 10 mal pro Frame aufgerufen wird bei 500 fps verursacht std::vector 5'000 Memoryallokationen pro Sekunde, dass sind bei einer Programmdauer von 2 Spielstunden 180 Mio. Allokationen mehr als nötig. Verursacht durch ein einziges std::vector. std::tr1::array muss ich noch genau anschauen, was das genau macht, bevor ich etwas dazu sagen kann...

    da braucht man echt nicht weiter diskutieren... du hast irgendwas grundlegendes nicht verstanden.



  • Du renderst unabhängig von der logik und dem input. Logik muss man vom Rendering ja sowieso trennen, da du in einem logik-tick ja je nach hardware leistung unterschiedlich viele frames berechnen kannst.

    Ach so, ja das tue ich, ich dacht du meinst vielleicht in separaten Threads...

    bewegen wir uns echt auf so einem niveau?

    Wer weiss, mal sehen, was ich nach dem Studium mache... 😉

    da braucht man echt nicht weiter diskutieren... du hast irgendwas grundlegendes nicht verstanden.

    Nein das interessiert mich jetzt, was habe ich nicht verstanden?



  • Ishildur schrieb:

    da braucht man echt nicht weiter diskutieren... du hast irgendwas grundlegendes nicht verstanden.

    Nein das interessiert mich jetzt, was habe ich nicht verstanden?

    Zwischen dem:

    void f1()
    {
    int v[10];
    
    for(int i=0; i<10; ++i)
      v[i] = i;
    }
    

    und dem:

    void f2()
    {
    std::tr1::array<int, 10> v;
    
    for(int i=0; i<10; ++i)
      v[i] = i;
    }
    

    besteht ein Unterschied von ziemlich genau Nada(ich gehe mal davon aus dass std::tr1::array auch auf dem Stack liegt). Jedes mal wenn du eine der Funktionen betrittst wird auf dem Stack Speicher reserviert und beim Verlassen wieder freigegeben. Dieses Freigeben ist bei beiden Alternativen sehr schnell weil nur ein Stackpointer geaendert werden muss.
    Wenn du natuerlich sowas machst:

    void f3()
    {
    std::vector<int> v(10,0);
    
    for(int i=0; i<10; ++i)
      v[i] = i;
    }
    

    Dann ist das ein riesen Unterschied weil jedes mal der Konstruktor und Destruktor des vectors aufgerufen werden muss.
    Da man aber wohl davon ausgehen kann dass du eine begrenzte, konstante Anzahl von Threads hast (wenn nicht sogar nur einen) kannst du deine(n) vector-Objekt(e) einfach als Member einer Klasse definieren.
    Beispiel fuer einen Thread:

    class TolleCppKlasse
    {
    public:
    TolleCppKlasse()
    {
    	v_.resize(10);
    }
    
    void f4()
    {
    for(int i=0; i<10; ++i)
      v_[i] = i;
    }
    
    private:
    	std::vector< int > v_;
    };
    

    Das ist wiederum exakt so schnell wie f1 und f2, aber du hast das ganze in ner schoenen Verpackung.
    Eine Implementierung fuer mehrere Threads ueberlass ich mal dir.



  • @rean
    Also das habe ich alles ganz genau verstanden... 😉

    besteht ein Unterschied von ziemlich genau Nada

    Wieso dann noch eine zusätzliche Bibliothek importieren, wenn ein natives Array genau dasselbe leistet?

    Dann ist das ein riesen Unterschied weil jedes mal der Konstruktor und Destruktor des vectors aufgerufen werden muss.

    GENAU! Darauf habe ich ja die gaaaaanze Zeit hingewiesen!!! :p

    kannst du deine(n) vector-Objekt(e) einfach als Member einer Klasse definieren

    Bei Singlethreaded Applications sicher eine elegante Möglichkeit, ich habe jedoch eine Multithreaded Application (Der Resourcenmanager sowie der INetworkService laufen jeweils in einem separaten Thread und dann muss ich diese (als Member deklarierte) Hilfsstruktur noch synchronisieren. Wenn das Teil auf dem Stack liegt, ist diese Synchronisation hinfällig weil jeder Thread sein eigener Stack hat.



  • Ishildur schrieb:

    Wieso dann noch eine zusätzliche Bibliothek importieren, wenn ein natives Array genau dasselbe leistet?

    so eine array klasse hat man einfach.
    Denn sie ist einfach besser als ein nacktes array.

    Bei Singlethreaded Applications sicher eine elegante Möglichkeit, ich habe jedoch eine Multithreaded Application (Der Resourcenmanager sowie der INetworkService laufen jeweils in einem separaten Thread und dann muss ich diese (als Member deklarierte) Hilfsstruktur noch synchronisieren. Wenn das Teil auf dem Stack liegt, ist diese synchronisation hinfällig weil jeder Frame sein eigener Stack hat.

    dh du berechnest frames parallel? finde ich strange.
    aber bitte, dann packt man den vector halt auf den stack (sprich verwendet einen stackbasierten container), ist ja kein problem. ich sehe nur ein generelles konzeptproblem wenn jeder frame den du berechnest alles neu machen muss - du hast keine daten die du vom letzten frame übernehmen kannst um zB effektiveres caching zu machen?

    PS:
    du widersprichst dir selbst aber oft.
    einmal wird das array wiederverwendet und ist deshalb so schnell weil nur ein zeiger umgebogen werden muss und einmal wird nichts wiederverwendet, etc. sehr verwirrend...



  • Ishildur schrieb:

    @rean
    Also das habe ich alles ganz genau verstanden... 😉

    besteht ein Unterschied von ziemlich genau Nada

    Wieso dann noch eine zusätzliche Bibliothek importieren, wenn ein natives Array genau dasselbe leistet?

    Dann ist das ein riesen Unterschied weil jedes mal der Konstruktor und Destruktor des vectors aufgerufen werden muss.

    GENAU! Darauf habe ich ja die gaaaaanze Zeit hingewiesen!!! :p

    kannst du deine(n) vector-Objekt(e) einfach als Member einer Klasse definieren

    Bei Singlethreaded Applications sicher eine elegante Möglichkeit, ich habe jedoch eine Multithreaded Application (Der Resourcenmanager sowie der INetworkService laufen jeweils in einem separaten Thread und dann muss ich diese (als Member deklarierte) Hilfsstruktur noch synchronisieren. Wenn das Teil auf dem Stack liegt, ist diese Synchronisation hinfällig weil jeder Thread sein eigener Stack hat.

    Weil ein vector dir viel mehr Funktionalitaet bietet als ein blankes Array:
    http://cplusplus.com/reference/stl/vector/
    http://cplusplus.com/reference/algorithm/
    Ich bin mir sicher dass du einige dieser Funktionen entweder selbst programmiert oder C-Funktionen dafuer verwendet hast.

    Wenn beide wirklich die selbe Funktionalitaet brauchem kannst du entweder jedem einfach ein Objekt der Klasse geben, damit hast du wieder getrennte Speicher, oder du verwendest eben ein vector-array und holst dir ueber die thread-id den passenden vector:

    class TolleCppKlasse
    {
    public:
    TolleCppKlasse()
    {
        v_.resize(2);
        for( int i = 0; i < anzahl_threads; ++i )
        {
            v_[i].resize(10);
        }
    }
    
    void f4()
    {
    std::vector< int > &cur_vec = v_[getThreadID()];
    for(int i=0; i<10; ++i)
      cur_vec[][i] = i;
    }
    
    private:
        std::vector< std::vector< int > > v_;
    };
    

    War das jetzt so schwer?
    Ich glaube dein Problem ist dass du nicht weisst was dir die STL alles bietet, schau dir mal die Links oeben an.



  • rean schrieb:

    Ishildur schrieb:

    @rean
    Also das habe ich alles ganz genau verstanden... 😉

    besteht ein Unterschied von ziemlich genau Nada

    Wieso dann noch eine zusätzliche Bibliothek importieren, wenn ein natives Array genau dasselbe leistet?

    Dann ist das ein riesen Unterschied weil jedes mal der Konstruktor und Destruktor des vectors aufgerufen werden muss.

    GENAU! Darauf habe ich ja die gaaaaanze Zeit hingewiesen!!! :p

    kannst du deine(n) vector-Objekt(e) einfach als Member einer Klasse definieren

    Bei Singlethreaded Applications sicher eine elegante Möglichkeit, ich habe jedoch eine Multithreaded Application (Der Resourcenmanager sowie der INetworkService laufen jeweils in einem separaten Thread und dann muss ich diese (als Member deklarierte) Hilfsstruktur noch synchronisieren. Wenn das Teil auf dem Stack liegt, ist diese Synchronisation hinfällig weil jeder Thread sein eigener Stack hat.

    Weil ein vector dir viel mehr Funktionalitaet bietet als ein blankes Array:
    http://cplusplus.com/reference/stl/vector/
    http://cplusplus.com/reference/algorithm/
    Ich bin mir sicher dass du einige dieser Funktionen entweder selbst programmiert oder C-Funktionen dafuer verwendet hast.

    Wenn beide wirklich die selbe Funktionalitaet brauchem kannst du entweder jedem einfach ein Objekt der Klasse geben, damit hast du wieder getrennte Speicher, oder du verwendest eben ein vector-array und holst dir ueber die thread-id den passenden vector:

    class TolleCppKlasse
    {
    public:
    TolleCppKlasse()
    {
        v_.resize(2);
        for( int i = 0; i < anzahl_threads; ++i )
        {
            v_[i].resize(10);
        }
    }
    
    void f4()
    {
    std::vector< int > &cur_vec = v_[getThreadID()];
    for(int i=0; i<10; ++i)
      cur_vec[i] = i;
    }
    
    private:
        std::vector< std::vector< int > > v_;
    };
    

    War das jetzt so schwer?
    Ich glaube dein Problem ist dass du nicht weisst was dir die STL alles bietet, schau dir mal die Links oben an.



  • @Shade of Mine

    so eine array klasse hat man einfach.
    Denn sie ist einfach besser als ein nacktes array.

    Ja Papi... :p

    dh du berechnest frames parallel? finde ich strange.

    Vergiss nicht, das ist erst mein 2. Spiel, ich bin also noch nicht so erfahren und muss noch viel lernen, keine Frage 😉 Habe im 3. Semester ein XBox360 Spiel mit XNA gemacht, könnte ich da nochmal anfangen, würde ich auch einige Dinge anders machen und das wird bei diesem Projekt sicherlich auch der Fall sein. In 2-3 Jahren werde ich zurückblicken und darüber lachen, was ich heute hier zusammen hacke und wie naiv ich doch damals (jetzt) gewesen bin :p

    Aber um deine Frage zu beantworten, nein ich berechne keine Frames parallel. Ich habe wie 3 parallel laufende Schleifen und an ganz bestimmten Stellen, greifen die Threads auf gemeinsame Daten zu, so nach dem Producer/Consumer Prinzip. Bspw. verarbeitet der INetworkService alle (asynchron) empfangenen UDP Packete und legt schliesslich Notification Messages in eine Queue. Diese Queue wird dann vom GameLoop im Mainthread einmal pro Frame abgefragt. Ähnlich verhält es sich mit dem IResourceService. Der GameLoop legt LadeBefehle in eine Queue, und der IResourceService lädt dann (innerhalb des Threads sequentialisiert) alle Resourcen für die ein LadeBefehl in der Queue steht.


Anmelden zum Antworten