ein absolut "kranker" fehler
-
@Mis2Com:
jo, std::fstream hat auch ne open methode und close. Aber die streams sind ja auch mies designt. Der Designer davon (hab leider den namen vergessen) gibt es ja auch zu und hat gemeint, dass er einiges anders machen wuerde, wenn er sie neu designen koennte.@otze:
natuerlich ist es schneller alles zuerst in den speicher zu laden.
die streams sind ja auch nicht fuer das schnelle auslesen aus einer datei gemacht - sie puffern ja wie wildbtw: was misst du denn da? nur das seek alleine? und das ganze auslesen dass du im open machst, ignorieren wir schoen... nicht sehr representativ...
und bitte: verwende exception und den ctor und dtor statt open und close. wenn du nicht weisst warum, google mal nach RAII
nix fuer ungut, aber deine klasse ist nicht so toll.
zB bei einem 100MB file stehst du an.ausserdem allokiert deine read methode keinen speicher - somit ist dein urspruenglicher code (mit dem ach so mysterioesen fehler) fehlerhaft.
-
shade? ich glaub wir reden aneinander vorbei
die read methode darf garkeinen speicher allokieren, das würde zu gigantischen speicherleaks führen.
wenn ne datei geöffnet wird, wird entweder sofort oder mittels open ein stream auf die zieldatei geöffnet, sie wird vermessen, dann mit dem wert der speicher reserviert, und die datei reingeschrieben.
wenn die klasse den scope verlässt wird der platz wieder freigegeben.
die read methode soll dann nur angeforderte mengen speicher in einen anderen speicherbereich transferieren.
read darf nicht new/malloc benutzen,was man auch an folgendem code sehen kann:header Header; datei.open("file.txt"); datei.read((*void)(&Header),sizeof(header));//hier ein new und wir haben ein schönes speicherleck,der cast muss da sein, //da ich keine templates benutzen kann,und deshalb eine version für void zeiger machen musste^^ //anderes Beispiel char data[256]; datei.read(data,256);//speicherleck bei new char* subdata=new char[256]; datei.read(subdata,256);//keiner erklärung mehr von nöten
zum thema open und ausmessen...seek wird andauernd durchgeführt read auch,open dagegen fast garnicht, also wieso testen? ist uninteressant,was nu länger braucht.
Und 100mb Files sind ne schöne sache, die werden nur partweise ausgelesen,oder direkt mittels stream,daran hab ich schon gedacht.
andererseits haben zb modeldaten die angewohnheit, dass man da wild rumseeken muss,und da hat so ein memorystream einen echten heimvorteil
-
result Virtualfile::read(char* &buffer,unsigned int bytes){
if(datapointer!=NULL){
if(position+bytes<size){
for(unsigned int i=0;i<bytes;++i){
buffer*=readpointer[position+i]; // KUCKUCK
}
position+=bytes;
return ok;
}
return out_of_range;
}
return stream_not_open;*Ob ich C++ kann oder nicht, ist mir jetzt egal, Fakt ist, dass du in der Zeile [i]KUCKUCK* diesen Buffer, den man übergibt, beschreibst und dafür dass du ihn beschreibst, muss Speicher vorhanden sein, den du nicht allokiert hast.
Und es handelt sich auch nicht um irgendeinen Stream, auf den du schreibst, du schreibst in den Buffer und der ist nicht definiert, da du bisher einfach einen Zeiger angelegt hast, der irgendwo hin zeigt.Jedenfalls sehe ich das so:
void irgendwas(char*& bla) { for(int n = 0; n < 100; ++n) bla[i] = 'a'; // irgendwas } char* a; irgendwas(a);
Somit schreibst du irgendwo in den Speicher, ob es da hingehört oder nicht.
Das Ergebnis sollte undefiniert sein, oder nicht?
In diesem Fall MUSS Speicher allokiert werden und das ist nicht im Gegenteil ein Speicherleck, es sei denn, du vergisst delete natürlich.Nagut, offensichtlich bin ich blind, man kläre mich auf...
-
wenn ich ausserhalb der funktion speicherplatz für ein objekt reserviere, und innerhalb der funktion dann mit einer referenz auf dieses objekt(bzw dem zeiger auf den speicherplatz den das objekt reserviert hat)arbeite,dann brauch ich nicht nochmal speicherplatz reservieren, denn er ist ja schon reserviert.
und nun stellen wir uns mal vor, ich reserviere ausserhalb der funktion speicher, übergebe den zeiger auf diesen speicher, und versuche dann mittels new nochmal speicher für diesen pointer zu reservieren.
ich kann nur vermuten was passieren kann:
1. undefiniertes verhalten
2. der pointer zeigt auf den gleichen bereich
3. der pointer wird einem neuen bereich zugeordnet, dabei entsteht ein speicherleck, da der vorher reservierte speicher nichmehr deleted wird.
//edit nach selbstversuch: 3 trifft zues besteht natürlich wie man in meinem ersten veralteten beispiel sehen kann die gefahr, illegal speicher zu belegen,aber solange mir niemand sagen kann,wie man testen kann, ob speicher reserviert wurde, bleibt das so.
-
Dein read-Methode stellt in keinem Fall Speicher für buffer bereit, wenn doch, so zeige mir die Zeile.
-
hallo? liest du überhaupt was ich schreibe? ich will garkeinen speicher zur verfügung stellen.
ich will als funktionsparameter einen zeiger auf einen speicherbereich,den der programmierer in irgendeiner weise schon freigegeben hat.
seis new, oder einfache reservierung des speichers auf dem stack, das is mir egal.
es ist also die schuld des benutzers der read funktion, wenn er undefiniertes verhalten erhält,das hab ich aber auch schon irgendwo geschrieben bzw eingeräumt, da ich ja am amfang denselben fehler gemacht hab(auch wenn der eigentliche fehler woanders lag).
-
Selber hallo.
Du schreibst in deiner Funktion in buffer rein und zwar recht viel.
Und dieser Speicher ist NIRGENDWO allokiert, in deinem Beispiel nicht außerhalb und innerhalb der read-Funktion auch nicht, es ist mir völlig egal, was du willst, du kannst unallokierten Speicher nicht einfach vollschreiben.
Wenn du innerhalb der read-Funktion keinen Speicher bereitstellst, so musst du dies außerhalb tun, aber das tust du nicht, folglich schreibst du in nicht-allokierten Speicher.Seufz, was ist daran so schwer zu verstehen?
-
ok nochmal ganz ganz langsam extra für dich-.-
//dies ist jetzt ein erklärendes beispiel char bla[254] //es werden 254 bytes auf dem stack reserviert,sagen wir von der //datenposition 16 aus,der reserviertespeicher geht also von 16-259 cout<<bla//hier wird die datenposition also 16 ausgegeben //so irgendwo später im code nachdem eine datei geöffnet wurde data.read(bla,254); //hier wird der zeiger auf die position 16 und die info über die anzahl der zu //kopierenden daten(zufälligerweise die größe des vorher reservierten speichers)übergeben //innerhalb der funktion result Virtualfile::read(char* &buffer,unsigned int bytes){ //durch die übergabe des zeigers auf den speicherbereich 16 zeigt buffer nun auch auf 16(siehe funktionen und parameter) buffer[1]//da der buffer den wert 16 hat zeigt buffer[1] 1 bit weiter->17->innerhalb des reservierten bereichs also ok buffer=readpointer[position+i]//zulässig solange es im reservierten bereich bleibt //das selbe gilt für readpointer->malloc //usw usf
.
-
Ich bezog mich auf dieses Beispiel:
result Virtualfile::read(char* &buffer,unsigned int bytes){ if(datapointer!=NULL){ if(position+bytes<size){ for(unsigned int i=0;i<bytes;++i){ buffer[i]=readpointer[position+i]; } position+=bytes; return ok; } return out_of_range; } return stream_not_open; }
Außerdem klang es so, als wenn ein new außerhalb der Funktion ein Speicherleck produzieren würde, aber lass mal, ich versteh ja sowieso alles falsch.
-
otze schrieb:
die read methode darf garkeinen speicher allokieren, das würde zu gigantischen speicherleaks führen.
Exakt.
Beachte aber mal dein ursprüngliches Beispiel:int main(int argc, char* argv[]) { int blub;//ganz doll wundern^^ int i; vfile::Virtualfile file; file.open("3DSINFO.TXT");//datei in speicher einlesen char* data; file.read(data,file.get_size());//inhalt des speichers in variable for(unsigned int i=0;i<file.get_size();++i){ cout<<data[i];//ausgabe der datei,bei long double in der blub variable gibts access violation in module bla^^ } file.close(); cin>>i; return 0; }
data hat keinen Speicher...
Warum nimmt read() denn dann eigentlich den Zeiger by Reference?
wenn ne datei geöffnet wird, wird entweder sofort oder mittels open
Und genau das ist der Designfehler. Lass das open weg.
zum thema open und ausmessen...seek wird andauernd durchgeführt read auch,open dagegen fast garnicht, also wieso testen? ist uninteressant,was nu länger braucht.
seek? Ich seeke Quasi nie, denn seek ist lahm. Wozu sollte ich das tun?
Wenn ich seeken will, mappe ich den Inhalt der Datei in den RAM und operiere nur auf ihm -> ohne kopien.andererseits haben zb modeldaten die angewohnheit, dass man da wild rumseeken muss,und da hat so ein memorystream einen echten heimvorteil
Dann mach das ganze ohne Kopien. Du willst im Prinzip nur rum springen in der Datei -> wozu also Kopien erstellen?
Ich habe noch nie mit Models gearbeitet, aber ich würde es einfach in den RAM mappen und mir nur Zeiger auf die Interessanten stellen merken - uU lieber zuerst in ein parserfreundlicheres Format kompilieren.
-
sorry, dass ich etwas azsgetickt bin,ich versuch jetzt nochmal in ruhe alles zu klären.
also,wenn ich in einen externen buffer schreiben will hab ich ein grundsätzliches problem:ich weis nicht,ob genügend speicher bzw ob überhaupt speicher freigegeben wurde.
nun gibt es 2 möglichkeiten:
1.ich allokiere immer innerhalb der funktion speicher.
da gibt es 2 probleme:
a) der user kann nur mit pointern arbeiten,bzw müsste den von mir allokierten speicherplatz in ein normales objekt kopieren.
b)wenn der user schon im vorfeld speicher allokiert hat, geht der natürlich verloren, und auf den stack kann man halt nur durch kopieren aus dem heap sachen ablegen
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
3.ich allokiere nur bei bedarf
1 grundsätzliches problem:
man kann nur schlecht die menge von mit new allokiertem speicher rausbekommen, bei normalen arrays funktioniert sizeof,ich müsste also immer 2 überprüfungen bei jedem read vorgang durchführen..ich hab mich also für punkt 2 entschieden,und überlasse dem user die ganze arbeit.
new ausserhalb der funktion wirft nur ein speicherleck auf, wenn ich mich für punkt 1 entscheiden würde.@shade den fehler am anfang hab ich jetzt hier in diesem thread 3 mal zugegeben, wieso merkt das eigentlich keiner und reitet weiter drauf rum?
zeiger bei reference? hast eigentlich recht, ich weis nur nicht genau wiesehr sich der overhead beim erstellen und zerstören der zeiger ist...
seek brauch ich vorallem dann,wenn ich die dateien in ein handliches format bringen will(zb wenn ich von d3ds zu einem eigenen format konverte und danach wieder abspeicher),ohne das mappen in den memory dauert die ganze prozedur einfach zu lange.
ausserdem ist mein seek wirklich schnell im gegensatz zu dem der streamsaber nochmal eine grundsätzliche frage zu der mir ans herz gelegten ausnahmebehandlung
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?
oder wnen malloc den nicht genug memory fehler ausgibt(was doch eigentlich sehr unwahrscheinlich sein sollte oder?)
-
gr, also das ist mir jetzt nun auch klar, das ist genau so wie beim normalen read, ich hatte mich verdammt nochmal nur auf den falschen Code bezogen...
-
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 freigebenDies 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);//BOOMwarum 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?