Unangenehmes Problem mit sprintf_s



  • 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.


  • Administrator

    Als Ergänzung zu dem was Shade Of Mine und rean gesagt haben:

    Ishildur schrieb:

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

    1. Leistet das native Array nicht genau dasselbe. Siehe auch:
    http://www.c-plusplus.net/forum/viewtopic-var-t-is-265807.html
    2. Wieso zusätzliche Bibliothek? Die meisten aktuellen Kompiler bieten die Unterstützung für den Technical Report 1 an. std::tr1::array sollte somit bereits standardmässig vorhanden sein. Ansonsten kann man sich das schnell selber erstellen. Ist eine Sache von Sekunden. Nein, ich schreibe es nicht in Sekunden, sondern kopiere es in Sekunden aus dem Boost-Quellcode File raus und füge es bei mir ein 😉

    Ishildur schrieb:

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

    Schon, nur hast du völlig falsch Verglichen und deine Argumentation dazu war einfach nur falsch.

    Zudem muss ich noch das hier wirklich unterstreichen:

    Shade Of Mine schrieb:

    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...



  • @rean

    War das jetzt so schwer?

    Nein sicher nicht. Ich kritisiere ja aber auch niemanden, der die STL und die Standard C++ Library oder Boost oder Loki oder alles zusammen benutzt. Wichtig ist doch, dass die verwendeten Werkzeuge ihren Zweck erfüllen. 😉 Ich kritisiere allerdings auch niemanden, der das nicht tut und einen anderen Weg ausprobiert um zu sehen, wohin er führt...



  • @Dravere

    du widersprichst dir selbst aber oft.

    Wenn ich das tue, tut es mir leid, das ist kein Absicht.

    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...

    Ja das waren zwei verschiedene Beispiele. Einmal das Problem, dass wenn ich einen lokalen std::vector innerhalb einer Methode habe, da eben durchaus Speicher auf dem Heap alloziiert wird. Das mit dem Zeiger umbiegen war ein anderes Beispiel aber irgendwie bin ich da wohl abgeschweift



  • Ishildur schrieb:

    ...Wichtig ist doch, dass die verwendeten Werkzeuge ihren Zweck erfüllen. ;)...

    Was bezogen auf deinen Eingangspost jedenfalls scheinbar nicht gegeben ist.



  • Also die InGame Konsole läuft jetzt einwandfrei und der Parser, denn ich natürlich auch völlig falsch und nicht Standardkonform geschrieben habe, verarbeitet die Scripts fehlerfrei. In diesem Sinne hat sprintf_s seinen Zweck wahrlich nicht erfüllt... :p



  • Ishildur schrieb:

    Also die InGame Konsole läuft jetzt einwandfrei und der Parser, denn ich natürlich auch völlig falsch und nicht Standardkonform geschrieben habe, verarbeitet die Scripts fehlerfrei. In diesem Sinne hat sprintf_s seinen Zweck wahrlich nicht erfüllt... :p

    Wie ich bereits gesagt habe: die Design Entscheidungen mögen ja richtig gewesen sein (wir kennen die Umstände ja nicht) aber deine Argumentation ist falsch.


Anmelden zum Antworten