D3D Performance



  • @olleman

    a) prinzipiell sollte man keine "MANAGED-Buffer" während dem loop "locken/unlocken". das kostet viel performance, weil intern noch ein zweiter puffer existiert, der zur sicherung der daten benötigt wird, und der dann auch geupdateted wird (mehr oder weniger, vermute ich mal). auf jeden fall ist ein managed buffer eine gute sache, nur sollte man ihn nicht wärend dem rendern mit daten füllen.

    b) die Direct3DX-Fonts sind relativ langsam. die performance ist zwar ok, aber meine eigene fontklasse ist ca. 16 mal so schnell, wenn ich den kompletten bildschirm mit einer 8-punkt-font vollzeichne (bei 1280x1024@85 Hz, GF4 ti4600, PIV 1.6). meine fontklasse bringt dann über 800 fps, directx nur ca. 50. die fontklasse selber porgrammieren ist also längerfristig auf jeden fall nötig!



  • zu a) könntest du das etwas genauer erklären? 🙂 Ich weiß nicht, was ein "MANAGED-Buffer" ist 🙂

    zu b) ok, sowas hab ich schon befürchtet 😕 Werd ich irgendwann mal machen, aber erstmal alles verstehen 🙂



  • Wenn ich das richtig verstanden habe, legt DX, bei benutzung eines managed Buffer, intern eine Sicherheitskopie von dem Buffer an (das würde erklären dass man sich so beim minimieren-maximieren nicht um die Resourcen kümmern muss). Wenn du jetzt diesen Buffer oft locken musst (damit er beschrieben werden kann), speziell beim rendern, kostet das einiges an Performance weil der "Backupbuffer" auch beschrieben werden muss.



  • zu a)

    ich meinte managed-vertex-buffer.

    um dreiecke zu rendern benutzt du ja einen vertexbuffer mit:

    g_pdevice->CreateVertexBuffer( sizeof(vertices),0,D3DFVF_XYZRHW|D3DFVF_DIFFUSE,D3DPOOL_DEFAULT, &g_pvb, NULL );
    

    und für "D3DPOOL_DEFAULT" kann man auch "D3DPOOL_MANAGED" benutzen. falls dann das device verloren geht ("lost device"), dann mann mus diese puffer nicht updaten, wie das bei normalen der fall ist. wenn du z.b. ALT+TAb drückst und deine device verloren geht, dann musst die vertexbuffer ohne "MANAGED" neuerstellen und neu initialisieren, also mit daten füttern. standardmäßig benutze ich so gut wie immer MANAGED ausser es macht keinen sinn, und dass kann ich dir auch nur empfehlen. aber wenn du MANAGED-Buffer benutzt, dann auf gar keinen fall während der laufzeit "locken/unlocken", weil das updaten des buffers dann sehr lange dauert (relativ gesehen).

    c) "Timer"

    hier ist meine timer klasse. der performance-timer misst normalerweise im bereich von 1/100000 sekunde bis 1/2000000 sekunde je nach system (ich hab noch nie größere oder kleinere werte gesehen). das reicht locker aus um eine millisekunde hyperexakt zu messen.

    #pragma once
    
    #define WIN32_LEAN_AND_MEAN
    #include <windows.h>
    
    class CTimer
    {
    public:
    	CTimer(void);
    	~CTimer(void);
    
    public:
    	void Update(void); //Aktualisiert den Timer
    	void Reset(void);  //Benutzt den letzten Wert von Update als neuen Startwert
    
    public:
    	void GetHours(unsigned long *hours);               //Gibt die Anzahl der Stunden zurück, die bis zum letzten Aufruf von Update verstrichen sind
    	void GetMinutes(unsigned long *minutes);           //Gibt die Anzahl der Minuten zurück, die bis zum letzten Aufruf von Update verstrichen sind
    	void GetSeconds(unsigned long *seconds);           //Gibt die Anzahl der Sekunden zurück, die bis zum letzten Aufruf von Update verstrichen sind
    	void GetMilliSeconds(unsigned long *milliSeconds); //Gibt die Anzahl der Millisekunden zurück, die bis zum letzten Aufruf von Update verstrichen sind
    
    private:
    	LARGE_INTEGER Frequency; //Frequenz
    	LARGE_INTEGER Start;     //Startwert
    	LARGE_INTEGER Delta;     //Deltawert
    };
    
    #include "CTimer.h"
    
    CTimer::CTimer(void)
    {
    	QueryPerformanceFrequency(&Frequency);
    	QueryPerformanceCounter(&Start);
    	Delta.QuadPart=0;
    }
    
    CTimer::~CTimer(void)
    {
    }
    
    void CTimer::Update(void)
    {
    	LARGE_INTEGER end;
    
    	QueryPerformanceCounter(&end);
    	Delta.QuadPart=end.QuadPart-Start.QuadPart;
    }
    
    void CTimer::Reset(void)
    {
    	Start.QuadPart=Start.QuadPart+Delta.QuadPart;
    	Delta.QuadPart=0;
    }
    
    void CTimer::GetHours(unsigned long *hours)
    {
    	LONGLONG result;
    
    	result=Delta.QuadPart/(Frequency.QuadPart*3600);
    	if (result>UNSIGNEDLONG_MAX) result=UNSIGNEDLONG_MAX;
    
    	(*hours)=(unsigned long)result;
    }
    
    void CTimer::GetMinutes(unsigned long *minutes)
    {
    	LONGLONG result;
    
    	result=Delta.QuadPart/(Frequency.QuadPart*60);
    	if (result>UNSIGNEDLONG_MAX) result=UNSIGNEDLONG_MAX;
    
    	(*minutes)=(unsigned long)result;
    }
    
    void CTimer::GetSeconds(unsigned long *seconds)
    {
    	LONGLONG result;
    
    	result=Delta.QuadPart/Frequency.QuadPart;
    	if (result>UNSIGNEDLONG_MAX) result=UNSIGNEDLONG_MAX;
    
    	(*seconds)=(unsigned long)result;
    }
    
    void CTimer::GetMilliSeconds(unsigned long *milliSeconds)
    {
    	LONGLONG result;
    
    	result=(Delta.QuadPart*1000)/Frequency.QuadPart;
    	if (result>UNSIGNEDLONG_MAX) result=UNSIGNEDLONG_MAX;
    
    	(*milliSeconds)=(unsigned long)result;
    }
    


  • KXII schrieb:

    die Direct3DX-Fonts sind relativ langsam. die performance ist zwar ok, aber meine eigene fontklasse ist ca. 16 mal so schnell, wenn ich den kompletten bildschirm mit einer 8-punkt-font vollzeichne (bei 1280x1024@85 Hz, GF4 ti4600, PIV 1.6). meine fontklasse bringt dann über 800 fps, directx nur ca. 50. die fontklasse selber porgrammieren ist also längerfristig auf jeden fall nötig!

    Hast du den Vergleich evtl. auch noch gegen CD3DFont gemacht? Würde mich mal interessieren, da ich diese Art von Font eigentlich immer für recht sinnvoll hielt.

    Bye, TGGC (Der Held ist zurück)



  • mir ist gerade aufgefallen, das sich mein beitrag auf die font-klasse aus den sdk beispielen bezieht, also die CD3DFont-Klasse, und nicht die D3DXFONT font klasse aus den directx 9 extensions. allerdings hatte ich auch mal einen performance test mit der D3DXFONT, und falls ich mich noch richtig erinnere, dann war die ein bischen langsamer als die CD3DFont font klasse, insbesondere bei dynamischen strings, die also jeden frame einen anderen inhalt haben.
    beide klassen sind nicht schlecht, aber wenn man viel text darstellt, dann sind sie zu langsam. einen weiteren nachteil sehe ich auch in der flexibilität, denn man kann nur die original fonts verwenden, so wie sie in der ttf-datei definiert sind. man kann also keine benutzerdefinierten schriften benutzen (bunt, vorgerendert, mit glanz effekten, ... so wie in den alten spielen oder die diablo schrift (vom aussehen her)).



  • @KXII
    Weil wir grad beim Thema Timer sind. Ich hab ebenfalls eine Timer Klasse, welche intern die High Resolution Timer benutzt. Macht es eigentlich Sinn die Rückgabewerte von QueryPerformanceFrequency und QueryPerformanceCounter auszuwerten? Gibt es überhaupt noch moderne Rechner, die diese Timer nicht haben oder ist das mittlerweile standardmässig vorgeschrieben?



  • keine ahnung ob das standardmäßig vorgeschrieben ist, ich glaube aber nicht.

    ich werte die ergebnisse nicht aus, weils mir zu mühseelig ist, und weil ich bis jetzt noch keinen rechner gesehen habe, der den timer nicht unterstützt. selbst mein alter AMD mit 400 MHZ auf einem NONAME-Board unterstützt ihn, und das board ist schon ein paar jahre alt...

    falls mein programm auf nem 486er (-board) nicht laufen sollte ist mir das eigentlich egal, abgesehen davon, das so ein rechner sowieso nicht genug performance hat, um meine programme auszuführen.

    ich habe mich in den letzten jahren intensiv mit errorhandling beschäftigt, und ich bin zu dem entschluss gekommen, daß zu viel errorhandling keinen sinn macht, bzw. viel zu umständlich ist. wenn man schnell vorankommen will, sollte man sich nur um die wirklich wichtigen sachen kümmern, wie z.b. "file not found" oder "could not create directx-device". so sachen wie "out of memory", "timer-error" oder "file-write-error" treten zu 99.9% sowieso nicht auf, und sie abzufragen macht den quellcode nur unübersichtlich, und umständlich in der handhabung. ausserdem ist dann ab einer bestimmten "programmtiefe" jede zweite zeile eine errorabfrage, die in 99.9 % aller fälle negativ ist.

    ausserdem ist das auch gängige praxis (je nach software natürlich). das spiel "need for speed underground (PC)" z.b. kümmert sich so gut wie gar nicht um errorhandling. wenn man dort dateien einfach löscht, dann startet das spiel trotzdem nur das die entsprechenden sachen nicht angezeigt werden 😮 , oder die ogre engine, die hat auch an vielen stellen kein errorhandling (exceptions gibts es zwar, aber nicht für alle ereignisse, wie z.b. den timer oder new's)



  • Ich werte den Errorcode immer aus, einfach weil ich mal eine Timer Klasse geschrieben habe, die das immer für mich übernimmt. Diese hat dann einen Fallback der mit timeGetTime() arbeitet. Und so halte ich das auch für vernünftig.

    Das NSFU Beispiel ist in dem Fall wohl etwas schlecht gewählt. Denn wenn man ein File lädt und die Datei nicht das ist, bekommt man eigentlich einen Nullpointer und damit Access Violations. Dieser Fehler wird offensichtlich abgefangen. Würde das Spiel in diesem Moment einfach abstürzen, dann könnte man behaupten, das dieser Fehler nicht beachtet wird.

    Bye, TGGC (Der Held ist zurück)



  • @tggc

    obwohl wir beide nicht wissen können wie NFSU programmiert ist, bezweifle ich das das fehlen einer datei automatisch zu einem nullpointer führt 🙂 (du meinst bestimmt die alten c routinen...). wahrscheinlicher ist, daß die klasse (ich machs mal simpel, z.b. eine auto-klasse) eine Load funktion hat, und diese schon in den ersten zeilen erkennt das die datei nicht da ist (INALID_HANDLE_VALUE oder NULL wenn man noch die alten c routinen nutzt), und sich dann einfach beendet ohne was zu machen. das spiel "nutzt" dann die autoklasse ganz normal mit move" und "draw" nur da intern keine daten exisitieren passiert nichts.

    mir geht es nicht darum fehler prinzipiell unbeachtet zu lassen. mann kann ja schon fehler testen, und wenn sie eintreten, dann ignoriert man sie einfach indem die funktion/klasse nichts macht (die klasse einfach uninitailisiert lässt). z.B.:

    newBuffer=new char[size];
    
    if (newBuffer!=NULL)
    {
      hier ist alles ok
      wenn nicht genug speicher da ist, dann passiert halt nichts, aber wenn kümmerts, da der fall ja sowieso nie eintritt
    }
    

    oder

    void Auto::Load(void)
    {
      if (FileOpen()==true)
      {
        LoadDataFromFile(.......);
    
        AutoInitialized=true;
      }
    }
    
    void Auto::Draw(void)
    {
      if (AutoInitialized==true)
      {
        DirectX->DrawMyCar(); //falls die "auto-datei" in load nicht gefunden wurde, dann wird einfach nichts dargestellt
      }
    }
    

    mann könnte jetzt jeder funktion die mit new speicher reserviert oder jeder funktion die die timer klasse benutzt einen bool-rückgabewert geben der einen fehler anzeigt. aber schreib dir dann mal eine 500-1000 zeilen lange ladefunktion für dateien (3d-mesh oder sowas) die jede kleinigkeit berücksichtigt und darauf reagiert. dann ist der komplette code der laderoutine voller fehlerabfragen und mann sieht den ladecode vor lauter code nicht mehr. sowas finde ich sinnlos, es reicht die wichtigen sachen abzufragen und den rest ignoriert man. ich will ja niemanden überreden. aber ich selbst programmiere jetzt schon ne weile so, und ich komme viel schneller voran und meine programme wurden dadurch nicht spürbar instabilier/fehlerhafter, und vorallem ist der code viel übersichtlicher, weil ich jetzt nur noch 1% fehlerabfragen habe.


  • Mod

    KXII schrieb:

    @tggc

    obwohl wir beide nicht wissen können wie NFSU programmiert ist, bezweifle ich das das fehlen einer datei automatisch zu einem nullpointer führt 🙂 (du meinst bestimmt die alten c routinen...). wahrscheinlicher ist, daß die klasse (ich machs mal simpel, z.b. eine auto-klasse) eine Load funktion hat, und diese schon in den ersten zeilen erkennt das die datei nicht da ist (INALID_HANDLE_VALUE oder NULL wenn man noch die alten c routinen nutzt), und sich dann einfach beendet ohne was zu machen. das spiel "nutzt" dann die autoklasse ganz normal mit move" und "draw" nur da intern keine daten exisitieren passiert nichts.

    noch viel wahrscheinlicher ist, dass es einen resourcemanager gibt und wenn man auf eine datei zugreifen möchte die nicht vorhanden ist, dann wirft dieser eine exception. wenn auf diese datei zugegriffen wird und es entsteht innerhalb der ladefunktion ein fehler, dann schmeisst man ebenfalls eine exception. falls ein fehler vorhanden ist (z.b. die datei ist 0 lang) und man hat keine fehlerbehandlung bzw behandelt nicht diesen fehler, dann wird das programm irgendwo später hochfliegen ohne dass man genau weiß an welchem eingeschlichenem bug das genau liegt.

    wenn ein fehler auftratt, dann so zu tun als wäre nichts passiert ist ziemlich gefährlich, weil es folgefehler geben kann und am ende hast du ein spiel das nach 20h spiel plötzlich abpfeift und alle savegames dabei löscht... schwer reproduzierbar... und das liegt vielleicht nur daran weil auf der cd irgendwo ein kleiner 'flip im bit' vorgekommen ist den du in der laderoutine vielleicht bemerkt, aber die ganze zeit nicht als fehler behandelt hast.

    rapso->greeets();



  • @KXII: Leider konnte ich es hier zu spät im Forum posten, aber den Timer habe ich jetzt schon hinbekommen. Wie ich jetzt sehe, sogar richtig (Mit QueryPerformanceCounter) 🙂
    Aber bei meinem Rechner (P4 2,8) Hat der ne Frequenz von 3579545 😉



  • @rapso

    ob es wahrscheinlicher ist, das exeptions geworfen werden bezeifle ich, da das spiel einfach weiter läuft und keinerlei meldungen ausgiebt. warum sollte das es dann überhaupt expetions werfen? (eine diskussion darüber wie und wann es intern was macht (ob mit exceptions oder ohne) ist aber sowieso sinnlos)

    ich vermute, das dieser effekt hauptsählich dadurch entseht, da das spiel "ursprünglich" für die ps2 geschrieben wurde und dort viele fehlerabfragen unötig sind, weil man z.b. immer genau weiß wielviel ram man hat (...).

    deine annahme, das ein programm, welches einige "fehler" nicht behandelt, irgendwann hochfliegt (nach 20h oder so oder wegen falschen bits auf der cd) ist für mich nachvollziehbar, aber nur wenn man sehr schlecht programmiert, und die fehler tatsächlich so betractet werden, als ob sie nie eintreten würden. ausserdem, wie gesagt, meine ich nicht alle, sondern nur die unötigen, sollte man weglassen/ignorieren (nicht ganz ignorieren, sondern nur nichts machen und alles auf default stellen, oder sowas)

    wenn eine datei die länge 0 hat, dann kann man natürlich, wenn man will, ein programm so schreiben, das es abstürtzt, aber wenn man ordentlich programmiert dann sollte das kein problem sein und nie zu fehlern führen. auch falsche werte auf einer cd sind kein problem. man kann ja einfach werte die man ließt auf ihr gültigkeit prüfen und falls sie falsch sind dann einfach die klasse als "not initialized" makieren. ich weiß nicht was daran schwer sein sollte, dies im programmcode umzusetzen. folgefehler sehe ich dann wirklich keine, denn eine gekapselete klasse die load, move und draw hat, macht dann halt einfach nichts und liefert unter umständen für position oder winkel immer 0 zurück egal was man mit dem auto macht. egal ob "load" fehler hat oder sonst was.

    mir ist ein spiel, das bei "fehlern" falsche darstellungen produziert (wie z.b. ein auto das sich nicht bewegt oder nicht sichtbar ist) lieber, als ein programm, das bei jeder kleinigkeit eine msgbox aufpoppt, und dessen programmcode übertrieben viel komplexer und schwerer zu lesen und viel länger und umständlicher zu entwickeln ist. wie gesagt, das weglassen von fehlerbehandlung zwingt nicht automatisch zu folgefehlern, sofern man immer alles überprüft (auch wenn man dann nichts macht, was dazu führt, das es dem benutzer mitgeteilt wird)) und für die ganz wichtigen sachen kann man ja fehlerbehandlung einbauen, sei es mit exceptions oder ohne.

    falls du dem nicht zustimmen kannst dann bring ein konkretes beispiel, wo man erkennen kann, das "leichte" fehler, mit einer "ignorierenfehlerbehandlung" so wie ich es meine, zu nichtreproduzierbaren fehlern führen und das programm zum abturz bringen kann.



  • @olleman

    wieso aber? das ist doch extremgenau!

    der timer kann die zeit auf eine MIKROSEKUNDE (1/1.000.000) sehr genau messen und das reicht für alles aus!



  • @rapso

    mir ist da gerade noch was aufgefallen.

    dein untergangsscenario ist etwas übertrieben.

    wenn ein fehler auftratt, dann so zu tun als wäre nichts passiert ist ziemlich gefährlich, weil es folgefehler geben kann und am ende hast du ein spiel das nach 20h spiel plötzlich abpfeift und alle savegames dabei löscht... schwer reproduzierbar... und das liegt vielleicht nur daran weil auf der cd irgendwo ein kleiner 'flip im bit' vorgekommen ist den du in der laderoutine vielleicht bemerkt, aber die ganze zeit nicht als fehler behandelt hast

    warum sollte ein spiel alle savegames löschen 😕 nur weil vielleicht ein paar klassen werte zurückgeben, die keinen sinn machen (aus sicht des benutzers)

    wer sowas programmiert, der hat einen sehr üblen programmierstil!!!

    😃


  • Mod

    KXII schrieb:

    @rapso
    deine annahme, das ein programm, welches einige "fehler" nicht behandelt, irgendwann hochfliegt (nach 20h oder so oder wegen falschen bits auf der cd) ist für mich nachvollziehbar, aber nur wenn man sehr schlecht programmiert, und die fehler tatsächlich so betractet werden, als ob sie nie eintreten würden. ausserdem, wie gesagt, meine ich nicht alle, sondern nur die unötigen, sollte man weglassen/ignorieren (nicht ganz ignorieren, sondern nur nichts machen und alles auf default stellen, oder sowas)

    wenn eine datei die länge 0 hat, dann kann man natürlich, wenn man will, ein programm so schreiben, das es abstürtzt, aber wenn man ordentlich programmiert dann sollte das kein problem sein und nie zu fehlern führen. auch falsche werte auf einer cd sind kein problem. man kann ja einfach werte die man ließt auf ihr gültigkeit prüfen und falls sie falsch sind dann einfach die klasse als "not initialized" makieren. ich weiß nicht was daran schwer sein sollte, dies im programmcode umzusetzen. folgefehler sehe ich dann wirklich keine, denn eine gekapselete klasse die load, move und draw hat, macht dann halt einfach nichts und liefert unter umständen für position oder winkel immer 0 zurück egal was man mit dem auto macht. egal ob "load" fehler hat oder sonst was.

    mir ist ein spiel, das bei "fehlern" falsche darstellungen produziert (wie z.b. ein auto das sich nicht bewegt oder nicht sichtbar ist) lieber, als ein programm, das bei jeder kleinigkeit eine msgbox aufpoppt, und dessen programmcode übertrieben viel komplexer und schwerer zu lesen und viel länger und umständlicher zu entwickeln ist. wie gesagt, das weglassen von fehlerbehandlung zwingt nicht automatisch zu folgefehlern, sofern man immer alles überprüft (auch wenn man dann nichts macht, was dazu führt, das es dem benutzer mitgeteilt wird)) und für die ganz wichtigen sachen kann man ja fehlerbehandlung einbauen, sei es mit exceptions oder ohne.

    falls du dem nicht zustimmen kannst dann bring ein konkretes beispiel, wo man erkennen kann, das "leichte" fehler, mit einer "ignorierenfehlerbehandlung" so wie ich es meine, zu nichtreproduzierbaren fehlern führen und das programm zum abturz bringen kann.

    <sarkassmuss>
    du magst also kein spiel dass dir dauernt abpfeift weil etwas nicht vorhanden ist, du mußt also spiele mögen die dich nach studenlangen suchen nach dem 'gral' in den warnsinn treiben, denn da hat dann jemand, so smart wie er ist, keine abfrage dafür eingebaut ob der gral überhaupt geladen wurde und stellt das 'nichts' erfolgreich dar.</sarkassmuss>

    fehlerabfragen sind hauptsächlich für die entwicklung wichtig, nicht fürs finale spiel. irgend ein grafiker schreibt ein script dass eine bestimmte resource benötigt (eines von hunderten scripts), natürlich geht er davon aus dass es läuft, das script wurde vom compiler verifiziert und fertig, dass er eine resource dabei nicht findet bzw. sie deiner "ignorierenfehlerbehandlung" unterliegt und deswegen misst zurückliefert, das kann er ja nicht vorher wissen. vielleicht ändert ja auch jemand die versionsnummer und das script findet die resource dann erst nicht mehr.. aktuelle spiele haben durchaus mehr als 10'000 dateien und dort könnte eine fehlen, sowas ist qualitätstechnisch nicht gut, wenn man es einfach ignoriert.

    im ausgelieferten spiel sollte natürlich keine fehlermeldung wegen fehlender resourcen kommen, dieser fehler wird aber nicht deswegen fernbleiben weil er ignoriert wird, sondern weil vorher mittels fehlermeldungen die qualität gesichert wurde.

    ein konkretes beispiel darf ich dir nicht nennen, aber ich war bei einem Betatest eines grossen publishers dabei und die haben für die deinstallation den subfolder in einer datei gespeichert. ihr resourcemanager hat gross und kleinschreibung beachtet, jemand der das deinstallationstool geschrieben hat aber nicht, er hat also die datei auf platte gesucht, gefunden, wollte sie laden (aber falsche gross und kleinschreibung gehabt), dann hat er den standart path bekommen (sowas wie c:\\programme\) und dann hätte er alles von meinem rechner gelöscht was ich dorthin installiert hätte, ich hatte es zum glück unter d:\\beta\, aber viele viele andere leute durften danach ihren rechner neu installieren.... wegen "ignorierenfehlerbehandlung".
    und dass diese software unsicherwar, das kann man nicht direckt sagen, immerhin hat er erstmal die datei auf platte gesucht gehabt bevor er sie aufmachte... hätte deren resourcesystem eine exception geworfen, wäre das nicht passiert. und aufgefallen ist es denen wohl nicht, weil auf einem testrechner auf dem eh nix anderes installiert ist als deren spiel, wurde es sauber aus dem ordner entfernt (mit der "ignorierenfehlerbehandlung" lief es ja)

    ich hab schon oft erlebt dass leute ein catch(...) eingebaut hatten um einfach festzustellen dass ihre funktion fehlschlug und dann weitermachten, aber es tratten dann folgefehler auf an denen ich oft tagelang nach dem bug suchte.

    um es nochtmal zu sagen, exception und fehlerbehandlung sind für die entwicklung wichtig, nicht für das fertige spiel. und in einem größerem team mit tausenden von resourcen überblickt niemand das komplette projeckt, aber jeder sollte versuchen sich und andere vor fehlern abzusichern, denn je später man einen fehler beheben bzw finden muss, desto höcher ist der aufwand, das steigt mit einer e^x funktion.

    rapso->greets();

    btw: "nur die unötigen, sollte man weglassen/ignorieren"
    da stimm ich dir zu, da stimmt dir jeder zu, der satz klingt aber zu öko 🙂



  • Um nochmal auf das Argument "Ohne Fehlerbehandlung ist der Code viel kürzer und klarer" einzugehen:

    Genau dafür sind Exceptions doch da.

    Objekt * neuesObjekt = erstellMirEinNeuesObjekt();
    neuesObjekt->blablabla();
    

    Würde ich ohne Exceptions arbeiten müßte ich sicherlich prüfen, ob die Funktion nicht 0 zurückgeliefert hat, weil anderenfalls ja der Methodenaufruf schief geht. Insofern ist die Fehlerüberprüfung mehr Aufwand, ja.
    Wenn die Funktion aber so geschrieben ist, daß sie eine Exception wirft, wenn etwas schief geht, dann kann ich mir die Überprüfung sparen, weil ich entweder ein funktionstüchtiges Objekt bekomme, oder ich die gefährliche Codestelle garnicht erreiche.

    Exceptions wurden genau zu diesem Zweck eingeführt, um die Fehlerbehandlung aus dem restlichen Code herauszulösen. Also nicht an jeder Stelle überprüfen, ob alles geklappt hat, sondern immer wenn was schiefgeht ne Exception werfen. Dann brauchen sich keiner der die Funktion benutzt noch Gedanken über Fehlerbehandlung machen.

    MfG Jester



  • @rapso

    ich habe keine lust (wie das früher auch schon oft der fall war) auf deine "seltsamen beispiele" einzugehen. ließ die erst mal den text von anfang an durch, dann wirst du feststellen, das ich gesagt habe, das man nicht vorhandene dateien schon abfragen sollte, weil sowas zu den wichtigen sachen gehört. wenn jetzt aber eine datei die vorhanden ist, nur die länge 0 hat, dann ist das was 99.9999% aller fälle sowieso nicht eintritt, weil der grafiker bestimmt kein 3dobjekt generiert, das eine leere datei hat. (ich weiß man könnte jetzt wieder gegenargumentieren, wenn aber doch, was dann,.... blablabla... das kann man aber immer. ein spiel entwickelt sich und man muss die fehler die enstehen nach und nach eliminieren, und dann weiß man auch grob woran es liegt, wenn ein objekt nicht oder nur teilweise dargestellt wird)

    hier nur ein paar kurze worte zu deinem beitrag:

    a) wenn von 10.000 dateien eine fehlt dann würde ich das natürlich auch bemerken, weils zu wichtigen sachen gehört (wie ich ganz am anfang geschrieben habe).

    im ausgelieferten spiel sollte natürlich keine fehlermeldung wegen fehlender resourcen kommen, dieser fehler wird aber nicht deswegen fernbleiben weil er ignoriert wird, sondern weil vorher mittels fehlermeldungen die qualität gesichert wurde.

    ^^das ist doch lächerlich. meine vorgehenseweise schließt das doch nicht aus (wie oben geschrieben)! und selbst wenn ich es nicht überprüfen würde (wie bei NFSU) was solls. glaubst du etwa ich würde ein spiel ausliefern das nicht getestet wurde??? sowas würde ich dann "blind argumentieren" nennen!

    b) wer ein setup/deinstallationsprogramm schreibt, das einfach ordner samt inhalt löscht, ist selber schuld! sowas nenn ich pfusch, bzw. sowas ist schlecht programmiert und verantwortungslos. besser man erstellt eine datei mit allen dateien samt pfad und löscht nur exakt die die in der datei stehen. wenn sie nicht existiert dann passiert halt nix. im normalfall (99.999% aller fälle) sind die dataien aber da und sie werden gelöscht. ein fehlerscenario wie du es beschreibst kann dann nicht eintreten.

    die dinge, die ich ignoriere, sind sachen die in der entwicklung nie eintreten werden, wie z.b. "out of memory bei new", und die auch beim enduser nie eintreten, weil z.b. gesagt wird das das programm mindestens 150 mb freien arbeitsspeicher braucht. wer dann halt schon seine 1.96 GB ram belegt hat und dann das spiel startet, der hat dann halt eben pech gehabt, weil eine "hauptabfrage" am anfang testet wieviel speicherplatz noch frei ist und wenn es weniger als 150 mb sind dann gibts ne fehlermeldung. jetzt aber beim tatsächlichen reservieren mit "new" zu testen ob noch genug speicherplatz da ist, das macht keinen sinn, da der fall zu 99.932764% (um genau zu sein) nie eintritt. oder wer schafft es nach dem doppelklick auf die spiel.exe noch schnell im hintergrung 150mb ram zu allokieren. das machen doch nur vollidioten! im spiel selber kann man ja auch an verschiedenen stellen nochmals das ram testen, z.b. kurz bevor ein level geladen wird. dann wiederholt sich der fall wie oben beschrieben nocheinmal.

    prinzipiell habe ich den eindruck, du hast gar kein interesse an neuen ideen. ich habe gesagt das man nicht alle fehler ignorieren soll, aber genau das machst du. deine argumente sind ganz spezielle einzelfälle, die man IMMER konstruieren kann. das hat aber mit dem was ich sage nichts zu tun. wenn du spass daran hast jede kleinigkeit zu überprüfen, dann mach es halt! mir ist es lieber, ich habe in 1-2 jahren ein geiles spiel programmiert das unter "standardbedingungen" läuft und das mir und meinen freunden spass bereitet, als ein programm das alle weltuntergangsmöglichkeiten beachtet, aber 20 jahre braucht bis es fertigentwickelt ist; dann aber gibt ja directx 77 und ich muss wieder alles umschreiben :((, das dauert dann wieder 10 jahre, und dann kurz bevor ich fertig bin und noch nie spass mit dem spiel haben durfte, schlägt ein 50-kilometer-durchmesser-komet auf der erde ein und das wars dann!

    also wenn du keine konkreten fälle nennen kannst, die meine vorgehenseweise unter allen umständen als sinnlos wiederlegen, dann lass es gut sein!



  • Du irrst dich. Genau DU brauchst mit deiner Methode 20 Jahre, davon suchst du 19 Jahre nach einem Fehler.


  • Mod

    ja ich hab auch keine lust drüber zu diskutieren,

    falls du dem nicht zustimmen kannst dann bring ein konkretes beispiel, wo man erkennen kann, das "leichte" fehler, mit einer "ignorierenfehlerbehandlung" so wie ich es meine, zu nichtreproduzierbaren fehlern führen und das programm zum abturz bringen kann.

    ch habe keine lust (wie das früher auch schon oft der fall war) auf deine "seltsamen beispiele" einzugehen.

    ich bin immer offen für neue sachen, ich habe keine preferenzen opengl oder d3d gegenüber, ich code pascal/delphi/java/assembler/profan/c#... genau so gern wie c++, ich mag es auf algorithmenebene zu optimieren genau wie auf assembler ebene und ich hab früher auch 'tolleranten' code geschrieben und alleine zu coden war so ok und vielleicht mit 1 oder 2 grafiker zusammen zu arbeiten war so auch ok, denen konnte man mit der zeit vermitteln worauf sie achten müssen.

    ich hab aber gelernt dass es zuviel aufwand beim bereinigen dieser tolleranten fehler gibt. dennn ein fehler bleibt ein fehler bleibt ein fehler und irgendwann möchte jemand dass der fehler weg ist und dann sitzt man lange dran anstatt das problem bei der wurzel zu packen.

    du ließt meine posts midestens so ungenau wie ich deine, aber in deinem lese ich wenigstens wertneutrale aussagen heraus wie "wenn es nicht nötig ist macht man es nicht", "soviel davon dass es ausreicht", ich hab nichts anderes je behauptet.
    das ist auch nicht der unterschied unserer auffasungsgaben. der unterschied ist, dass ich ein programm kontrolliert abbreche sobald ein fehler auftaucht, damit er bereinigt werden kann. du lässt es weiterlaufen. DU weißt was mit deinem coden passieren kann wenn der fehler drinne ist und es weiter läuft, aber wenn du von 10 leuten 'tolleranten' code hast, dann weißt du am ende nicht ob die auftrettenden nebeneffeckte wirkliche bugs sind oder nur durch die 'fehlertolleranz' von deren code verursacht wurden.
    und solange man den fehler nicht fixen muss, wird in der entwicklung jeder den fehler dahinschleifen lassen bis zur masterphase in der man panisch versucht alles auszumerzen und hofft dass jeder noch weiß wo ein 'tolleranter' bug drinne war.

    rapso->greets();


Anmelden zum Antworten