Problem mit Streams in Klassen
-
Hallo,
Ich habe in einer Klasse einen FileSteam privat deklariert und möchte ihn in einer Unterfunktion erstellen. Mein problem: Ich bekomme jedesmal einen Zugriffsfehler.
class Test { private: TFileStream *HFile; public: int LoadFromFile(AnsiString Filename); }; ///////////////////////////////////////////////// int Test::LoadFromFile(AnsiString Filename) { HFile = new TFileStream (Filename,fmOpenRead); ..... }Der Fehler kommt bei der Zeile " = new TFileStream", ich habe shcon einiges versucht weiß aber nicht weiter. Kann mir da jemand helfen?
Und nocheine frage:
Wenn ich diesen Stream in eine Funktion als FileStream nutzen will und in eienr anderen als MemoryStream, ist soetwas auch möglich?
MfG Jukka~
-
Hi,
hab gerade mal deinen Quellcodeausschnitt per copy & paste in ein neues Förmchen gepackt, läuft ohne Fehler bei mir.Wie genau heisst denn deine Fehlermeldung?
Aus der BCB Hilfe zu TFileStream:
Wenn die Datei nicht geöffnet werden kann, löst TFileStream eine Exception aus
Könnte das dein problem sein?
-
---------------------------
Test
---------------------------
Access violation at address 00403146 in module 'Test.exe'. Write of address 00000000.
---------------------------
OK
---------------------------Das passiert bei jeder Datei. Angeblich will der in null schreiben aber ich weiß nicht warum.
-
Hallo
Vermutlich rufst du die LoadFromFile für eine ungültige Instanz von Test auf, der Zugriff auf HFile ist nur der Auslöser. Ein anderer Fehlergrund ist aus dem geposteten Quellcode jedenfalls nicht zu sehen.
Btw. ist vermutlich der TFileStream Pointer als Klassenmember ein Konzeptfehler. Bist du sicher das du auch außerhalb von LoadFromFile die FileStream-Instanz brauchst? Der Name der Methode deutet (analog TStringList...) doch eher darauf hin das die Methode die Daten ganz aus dem Stream ausliest und danach den Stream nicht mehr braucht. In diesem Falle sollte der Pointer aber lokal in der Methode deklariert werden und natürlich auch der FileStream am Ende der Methode wieder gelöscht werden.
Brauchst du die Instanz wirklich Methodenübergreifend solltest du entweder unbedingt mit Konstruktor/Destruktor arbeiten um den Pointer auf NULL zu setzen bzw. delete aufzurufen. Und auch solltest du bei LoadFromFile unbedingt erstmal eine bestehende Instanz hinter dem Pointer löschen bevor du dem Pointer eine neue Instanz zuweist. Sonst gibts ein Speicherleck. Das ganze könntest du natürlich auch einfach mit std::auto_ptr lösen.bis bald
akari
-
Ich brauche den Stream für Funktionen aus der Ganzen Klasse. Das ist nur ein Auschnitt daraus. Die Klasse wird für ein Dateiarchiv sein, LoadFromFile öffnet lediglich die datei liest den Header und die Dateiposition aus damit andere Funktionen (wie Add und Extract) diese Weiterwerwenden können.( Sozusagen ein Create) Ich wüsste keine andere Lösung als jedesmal die Datei neu zu öffnen, was jedoch sehr an der Laufteit zerrt.
Problem besteht ja darin das ich gleichzeitig auch einen MemoryStream mit gleichen namenbenötige (dynamic cast?) da es sich ja nicht nur um Dateien handeld, Und das ganez Gleich als MemoryStream zu betrachten geht auch nicht .. ich kann nicht eine 1GB Dati in den Speicher laden.Könnte mir da jemand einen rat geben? da ich mit std::auto_ptr nicht viel anfangen kann allein.
-
Hallo
Jukka schrieb:
Ich brauche den Stream für Funktionen aus der Ganzen Klasse. Das ist nur ein Auschnitt daraus. Die Klasse wird für ein Dateiarchiv sein, LoadFromFile öffnet lediglich die datei liest den Header und die Dateiposition aus damit andere Funktionen (wie Add und Extract) diese Weiterwerwenden können.( Sozusagen ein Create) Ich wüsste keine andere Lösung als jedesmal die Datei neu zu öffnen, was jedoch sehr an der Laufteit zerrt.
Okay das klingt in Ordnung. Ich würde allerdings die Methode nicht LoadFromFile nennen, weil das zu Mißverständnissen mit den VCL-typischen Methoden gleichen Namens führen kann. Statt desen lieber OpenFile, was klar macht das die Datei eben nicht wieder sofort geschlossen wird.
Nitzdestotrotz ergibt sich noch kein Fehlergrund. benutzt den Debugger und finde heraus wo die Methode aufgerufen wird und für welche Instanz.Problem besteht ja darin das ich gleichzeitig auch einen MemoryStream mit gleichen namenbenötige (dynamic cast?) da es sich ja nicht nur um Dateien handeld, Und das ganez Gleich als MemoryStream zu betrachten geht auch nicht .. ich kann nicht eine 1GB Dati in den Speicher laden.
Was verstehst du unter gleichnamig? Zur Laufzeit gibt es keine Variablennamen mehr, nur noch Speicheradressen. Und du darfst auch nicht TFileStream in TMemoryStream per dynamic_cast umwandeln, da kommt nämlich NULL raus. Vielleicht ist das der eigentliche Speicherzugriffsfehler? Warum brauchst du unbedingt TMemoryStream? Schließlich sind beide Klassen von TStream abgeleitet, so das du mit TFileStream so arbeiten könntest wie mit TMemoryStream ohne alles in den Speicher laden zu müßen.
Könnte mir da jemand einen rat geben? da ich mit std::auto_ptr nicht viel anfangen kann allein.
Ein einfaches Beispiel
#include <memory> class Test { private: std::auto_ptr<TFileStream> HFile; // Autopointer vom Typ TFileStream // Wird vom Konstruktor automatisch mit NULL initialisert wenn du nichts // anderes angibst. Und Destruktor löscht automatisch eine eventuell // vorhandene Instanz, was bei TFileStream völlig korrekt ist public: int LoadFromFile(AnsiString Filename); }; Boo(TStream* Stream); ... int Test::LoadFromFile(AnsiString Filename) { HFile.reset(new TFileStream (Filename,fmOpenRead)); // Löscht eine eventuell vorhandene Instanz und weist eine neue zu ..... Boo(HFile.get()); // So kommst du immer an den rohen Zeiger im Autopointer ran. // Natürlich darfst du niemals delete auf diesen Pointer aufrufen! }auto_ptr hat allerdings noch den Nachteil das es nicht richtig mit dem Kopierkonstruktor von Test zusammenarbeiten wird. Falls du also irgendwo Instanzen von Test kopierst must du zwangsläufig auch einen manuellen Kopierkonstrukor schreiben.
bis bald
akari
-
Wobei ich hier den Sinn von auto_ptr nicht mehr richtig einsehe. Der einzige Vorteil hier ist, das du auf einen Destruktor verzichten kannst. Da du hier eh einen CopyCtor brauchst, kannst du auch gleich einen Destruktor schreiben und einen normalen Pointer verwenden. Das ist aber letztlich Ansichtssache.
-
Die Methode mit dem auto_ptr bringt genau den gleichen Zugriffsefehler.
-
Hallo
akari schrieb:
Vermutlich rufst du die LoadFromFile für eine ungültige Instanz von Test auf, der Zugriff auf HFile ist nur der Auslöser. Ein anderer Fehlergrund ist aus dem geposteten Quellcode jedenfalls nicht zu sehen.
bis bald
akari