ein absolut "kranker" fehler



  • otze schrieb:

    2.ich allokiere nur ausserhalb der funktion speicher
    und wieder 2 probleme:
    a) vergisst der user speicher zu allokieren lande ich im undefinierten bereich
    b) der user muss immer genügend speicher im vorfeld freigeben

    Dies ist die richtige Methode.
    Der User übergibt ja als 2. Parameter die anzahl der Bytes die du lesen sollst 🙂
    Also weiss nur er wieviel speicher er braucht und kann das optimal einteilen.
    wenn der user zu dumm ist, speicher zu allokieren, ist das nicht deine schuld. detto beim freigeben des speichers.

    zeiger bei reference? hast eigentlich recht, ich weis nur nicht genau wiesehr sich der overhead beim erstellen und zerstören der zeiger ist...

    Kaum overhead. Aber es verwirrt. Mich hat es ziemlich verwirrt.

    ausserdem ist mein seek wirklich schnell im gegensatz zu dem der streams 😃

    Logisch. Denn die sind für lesen und schreiben gemacht - deins ist nur für lesen und fürs seeken.

    wie soll ich auf den fehler reagieren, dass der user einen unbekannten namen eingegeben hat, bzw mittem im programm eine nicht existente datei aufgerufen wird?

    du wirfst eine Exception, zB file_not_found() oder ähnliches.
    uU solltest du noch eine Funktion anbieten wo der user testen kann, ob es die datei gibt.

    um solchen code zu ermöglichen.

    vfile* f;
    if(file_exists("foobar"))
    {
      f=new vfile("foobar");
    }
    else
    {
      f=new vfile("other");
    }
    

    ein is_open wie die C++ streams ist doof. Denn wir wollen mit exceptions die Fehlerbehandlung nicht vorort vornehmen, sondern dort, wo wir darauf reagieren können.

    oder wnen malloc den nicht genug memory fehler ausgibt(was doch eigentlich sehr unwahrscheinlich sein sollte oder?)

    einfach bad_alloc weiter werfen



  • hmm shades kommentar im bezug aufs kopieren hat mich ins grübeln gebracht...
    vielleicht wär es ja einfach besser, wenn ich die read funktion so umschreibe,
    dass sie einen pointer eines objektes(im zweifelsfall void*)nimmt, und diesen pointer auf die aktuelle position des lesezeigers ausrichtet...das würde ja nochmal nen ziemlich großen performancegewinn bringen...

    gäbe es punkte die dagegen sprächen?

    //edit achja shade meine klasse kann auch schreiben,zu dem zweck sind write funktionen integriert sowie die >> operatoren überladen, welche bei jedem aufruf erstmal testen,ob noch genügend speicher vorhanden ist und im zweifelsfall reallock aufrufen(achtung hier würde es mit der veränderten read funktion probleme geben).desweiteren hab ich auch noch den [] operator überladen, der sofort den lesezeiger auf eine position ausrichten kann,ich könnte im moment also sehr wohl schreiben 😃



  • otze schrieb:

    vielleicht wär es ja einfach besser, wenn ich die read funktion so umschreibe,
    dass sie einen pointer eines objektes(im zweifelsfall void*)nimmt, und diesen pointer auf die aktuelle position des lesezeigers ausrichtet...das würde ja nochmal nen ziemlich großen performancegewinn bringen...

    Ich habe es so gemacht, dass die Datei als eine Art string representiert wird.
    Es gibt begin und end Zeiger, und was dazwischen steht, kann ich selber befuschen 🙂

    //edit achja shade meine klasse kann auch schreiben,zu dem zweck sind write funktionen integriert sowie die >> operatoren überladen, welche bei jedem aufruf erstmal testen,ob noch genügend speicher vorhanden ist und im zweifelsfall reallock aufrufen

    Das ist aber Arsch lahm...

    (achtung hier würde es mit der veränderten read funktion probleme geben).desweiteren hab ich auch noch den [] operator überladen, der sofort den lesezeiger auf eine position ausrichten kann,ich könnte im moment also sehr wohl schreiben 😃

    Man öffnet sowieso keine Datei zum lesen UND schreiben. Also erlaube das garnicht erst, und du bist das Problem los.



  • shade so lahm ist der test garnich wenn man bedenkt, dass mein "lesezeiger" nur den start der datei beschreibt, und seine "position" in einer int variable festgehalten wird.
    positionsabfragen werden dann mit lesezeiger[position] durchgeführt.
    der test is dann ne simple addition.ob das nun performant ist weis ich nicht, aber 10millionen vorgänge in 140ticks sind schnell genug denk ich mal^^

    //hier der test beim schreibvorgang 
    if(position+sizeofdata<=size)
    {
        /*schreibvorgänge usw*/
    }
    else
    {
        throw(out_of_range(write,datapointer,size+sizeofdata));
    }
    

    aber irgendwie nervts mich, dass ich durch mein interface keine templates benutzen darf..wie ist es eigentlich, wenn ich bei einer klasse den void* cast überlade und die klasse dann so wie sie ist der read/write(void*,int) funktion übergebe,würde der compiler dann direkt nach void casten?



  • otze schrieb:

    shade so lahm ist der test garnich wenn man bedenkt, dass mein "lesezeiger" nur den start der datei beschreibt, und seine "position" in einer int variable festgehalten wird.

    Ich meinte das realloc.

    aber irgendwie nervts mich, dass ich durch mein interface keine templates benutzen darf..

    Warum gehen keine templates?



  • gib mir ne schnellere(schönere) möglichkeit für reallock 😃

    und warum keine templates gehen?

    template<class T>
    virtual read(T,int);//BOOM
    


  • otze schrieb:

    gib mir ne schnellere(schönere) möglichkeit für reallock 😃

    Nicht alles an einem stück im speicher halten, zb nur in 4KB blöcken (also 1 pagesize)

    und warum keine templates gehen?
    virtual read(T,size);//BOOM

    warum muss read virtual sein?
    warum nicht op>> ?



  • read muss virtual sein, da es 2 klassen gibt, 2 streamklassen, die dasselbe interface benutzen.
    ziel war bzw ist es, die klassen austauschbar zu machen, damit die eine im notfall(zb malloc versagt) für die andre einspringen kann.
    und dann gehts halt nich anders...

    aber nur mal so aus neugierde: wie schaffst du es, eine datei in 4kb blöcke aufzuteilen? std::list?

    und wie muss ich in den streamklassen die funktionen aufbauen, damit sie einen überladenen >>/<< operatar einer anderen klasse akzeptieren?



  • otze schrieb:

    read muss virtual sein, da es 2 klassen gibt, 2 streamklassen, die dasselbe interface benutzen.

    schau dir diesbezüglich mal die c++ streams an

    ziel war bzw ist es, die klassen austauschbar zu machen, damit die eine im notfall(zb malloc versagt) für die andre einspringen kann.
    und dann gehts halt nich anders...

    wenn malloc einmal fehlschlägt, ist so ziemlich alles zu spät.

    aber nur mal so aus neugierde: wie schaffst du es, eine datei in 4kb blöcke aufzuteilen? std::list?

    jo. das wäre ne möglichkeit. uU auch ein vector.



  • 4kb sind eine pagesize, das ist klar.
    geht bei größeren datenblöcken denn die performance so stark in die Knie, dass es sich lohnt sie aufzuteilen, oder hat das andre gründe?

    //edit (ich edite zuviel)
    wiegroß ist eigentlich der heap bei nem rechner mit 500mb ram und ner 1gb auslagerungsdatei? in der hilfe steht nur, dass heap das ist, was nicht stack ist, und das ist sehr vage^^



  • Die Größe des Heaps hängt vom Betriebssystem und der Rechner-Architektur ab.

    Bei 32Bit-Systemen und Windows 9x hat das Programm grundsätzlich maximal 2GB zur Verfügung. Bei Windows NT/XP sind es erstmal auch nur 2GB, mit einem Trick bekommt man IMHO auch 3GB (eine Linkeroption).
    Alle Adressen, die das Programm erhält, liegen innerhalb dieser 2GB. Also auch der Code und der Stack. Der Heap wird also niemals die vollen 2GB ausnutzen können.
    Der physikalisch vorhandene RAM ist bei einem halbwegs ernstzunehmenden Betriebssystem unwichtig für die Größe des Heaps.

    Wenn du unter Windows programmierst, schau dir mal memory mapped files an. Vielleicht kannst du das gebrauchen. Dabei bildet Windows eine Datei auf RAM-Speicher ab. Dank virtuellem Speicher ist das auch mit großen Dateien möglich, ohne dass der Speicherverbrauch des Programms um ein Byte steigt.



  • cd9000 schrieb:

    Die Größe des Heaps hängt vom Betriebssystem und der Rechner-Architektur ab.

    Bei 32Bit-Systemen und Windows 9x hat das Programm grundsätzlich maximal 2GB zur Verfügung. Bei Windows NT/XP sind es erstmal auch nur 2GB, mit einem Trick bekommt man IMHO auch 3GB (eine Linkeroption).
    Alle Adressen, die das Programm erhält, liegen innerhalb dieser 2GB. Also auch der Code und der Stack. Der Heap wird also niemals die vollen 2GB ausnutzen können.
    Der physikalisch vorhandene RAM ist bei einem halbwegs ernstzunehmenden Betriebssystem unwichtig für die Größe des Heaps.

    Wenn du unter Windows programmierst, schau dir mal memory mapped files an. Vielleicht kannst du das gebrauchen. Dabei bildet Windows eine Datei auf RAM-Speicher ab. Dank virtuellem Speicher ist das auch mit großen Dateien möglich, ohne dass der Speicherverbrauch des Programms um ein Byte steigt.

    erstmal danke für die info,das hat mir sehr geholfen 😉
    zum thema memory mapped files...ich schreib ja dateien in den heap um vielfach schnelleren zugriff auf sie zu haben, wie ist das denn mit memory mapped files? gibts da geschwindigkeitszuwächse?

    //edit is der code so in ordnung?

    string Filename("datei.dat");
    HANDLE Filehandle=CreateFileForMapping(*Filename,GENERIC_READ,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL|FILE_FLAG_RANDOM_ACCESS);
    readpointer=CreateFileForMapping(Filehandle,NULL,PAGE_READONLY,0,0,NULL);
    //mit dem pointer arbeiten
    buffer[3]=readpointer[3];
    


  • Wenn du ne Datei in den Speicher mappst, dann liegt sie im Speicher. Genau wie deine Datei 🙂 nur dass das mappen schneller ist.



  • es gibt noch eine letzte frage,dann is dieses thema für mich abgeschlossen ;9
    shade, du hast ja ein paar posts vorher gesagt, dass es besser wär, den großen dateibuffer in 4kb große teile aufzuspliten.
    Jetzt mal ganz abgesehen davon, wie mam das am besten implementiert,wie kann ich folgende situation regeln?

    Ich hab jetzt also einen 25*4kb großen Buffer,und eine funktion will mithilfe eines pointers drauf zugreifen.
    so, nun haben wir ein problem:
    solange nur aus dem ersten der 25 teilbuffer gelesen wird ist alles in ordnung,
    will man aber das 4097.Byte lesen(also das erste byte des 2. buffers) trifft man auf eine ziemlich harte mauer: zwischen 2 buffern können x unbesetzte Bytes liegen,vom sprung von byte 4096 zu 4097 müssen also noch x bytes übersprungen werden,und das problem ist, dies dem pointer mitzuteilen...gibt es überhaupt eine möglichkeit, das zu regeln?

    also im endeffekt, soll es der funktion erlaubt sein den übermittelten void pointer umzucasten,und dann zb x=*pointer[4097] aufzurufen(das entspricht auch in etwa dem, was man "in freier wildbahn"(ergo D3DXCreateTextureFromFileInMemoryEx()) antrifft.



  • Das geht dann natuerlich nicht...
    Ich wuerde hier eine eigene Stringklasse empfehlen. Diese Klasse zeigt nur auf den Speicher wenn dies moeglich ist - wenn es nicht moeglich ist, muss eben doch kopiert werden. allerdings treten solche situationen ja hoffentlich nicht allzuoft auf (wenn doch, dann uU die Bloecke vergroessern).

    Aber du hast doch sowieso das Problem, dass du keine echten C strings hast, da du sie ja nicht gut NULL terminieren kannst...



  • null terminieren is das kleinste problem...
    25*4kb blöcke und der 26. block isn nullzeiger^^

    hm was haltet ihr denn von der idee:
    es ist klar, dass man nicht wirklich eine 100mb datei im speicher haben sollte.
    dann gäbs doch den alternativ weg, dass der user eine Klasse hat, die zuerst nur einen "suchstream" auf die datei öffnet.
    wenn der Programmierer dann an dem bereich ist, der für ihn nützlich ist, kann er einen xkb buffer erzeugen, der mit den daten gefüllt wird..
    der programmierer kann dann weiter suchen, und weitere buffer erzeugen,und dann mit diesen wesentlich kleineren buffern arbeiten.
    wenn man ihm dann noch die wahl zwischen "an einem stück" oder "in handlichen 4k blöcken" lässt, dürfte es dann auch bei funktionen die die pointer benötigen keine probleme geben.
    Vielleicht lässt man dem Programmierer aber auch eine weitere wahlmöglichkeit:
    wenn der programmierer weis, dass er einfach nur linear durch die datei durchmuss,dann würde sich vielleicht die anschaffung eines 100kb großen(in 4kb buffer aufgeteilt) Buffers lohnen, der sich sozusagen immer die nächsten 100kb streamt, und wenn man dann am ende ist, automatisch die nächsten 100 bekommt.die größe des Buffers da muss man vielleicht noch mit rum experimentieren, was die beste speicherleistung bei dem wenigsten performance verlust ist.



  • otze schrieb:

    null terminieren is das kleinste problem...
    25*4kb blöcke und der 26. block isn nullzeiger^^

    Das loest das Problem nicht.

    Ich kenne DirectX nicht, deshalb weiss ich nicht was fuer Strings es erwartet - aber sollten die nicht 0 terminiert sein? Wenn ja - wie machst du es dann?

    es ist klar, dass man nicht wirklich eine 100mb datei im speicher haben sollte.

    Wenn die Datei groesser als x MB ist, dann ladest du die Datei nur haeppchen Weise.

    zB liest du den ersten Block ein - wenn der User jetzt woanders hinseekt, laedts du den Block (uU halt auch mehrere Bloecke im RAM halten).
    So kostet das nachladen zwar etwas - aber ich nehme an die Algorithmen lassen sich so optimieren, dass sie nie weit seeken, so wird das nachladen minimiert.



  • ah shade dann haben wir uns missverstanden 😉
    directx will in solchen fällen nur ein zeiger auf das erste byte der datei im speicher und die größe der datei, also nix mit string klasse^^


Anmelden zum Antworten