EAccessViolat. bei Funktion-Verlassen [gelöst]



  • Guten Morgen Gemeinschaft,

    mal wieder stehe ich vor einem Rätsel: Ich habe ein Formular aus einem anderen Projekt kopiert und in ein neues Projekt eingebunden. Ich habe alle 4 Dateien (*.h, *.cpp, *.obj, *.dfm) im Windows-Explorer markiert und in einen neuen Ordner kopiert. Dann habe ich das Formular im neuen Projekt hinzugefügt. Das Formular interagiert nicht mit anderen Formularen, und benötigt keine zusätzlichen Dateien (Bilder, Bibliotheken etc).
    Im neuen Projekt wird das Formular nicht beim Programmstart erstellt. Zur Laufzeit wird auf Knopfdruck eine Instanz des Formulars erstellt. Im Konstruktor wird dann unter anderem eine ListBox mit Werten gefüllt

    for(unsigned short i=0; i<18; i++)
    { ListBox1->Items->Add(PutEntry(0, i)); }
    

    Die Funktion sieht so aus:

    AnsiString TFormXYZ::PutEntry(int Group, int Position)
    {
    	Eintrag= Vorlage[Group][Position];
    	Eintrag.Delete(Eintrag.LastDelimiter("~"),2);
    	return(Eintrag);
    }   // !!!
    

    Eintrag ist als AnsiString im Header unter private deklariert.
    Die Funktion ebenso:

    AnsiString PutEntry(int, int);
    

    .
    Vorlage ist global in der cpp:

    const AnsiString Vorlage[4][24]   // Edit: war "Wert[4][24]"
    

    Nun das Problem: Gleich nach dem 1. Durchlauf der Funktion wird an der mit "!!!" markierten Stelle ein EAccessViolation geworfen (ich fang sie immer auf, damit sie nicht kaputt geht 🤡 ). Ich bin ziemlich ratlos, was da schiefläuft. Es steht der gewünschte Inhalt in Eintrag. Hat jemand einen Hinweis für mich?



  • Hallo

    Aus dem gezeigten Quellcode läßt sich für uns keine eindeutige Fehlerursache herauslesen.

    Ich habe ein Formular aus einem anderen Projekt kopiert und in ein neues Projekt eingebunden. Ich habe alle 4 Dateien (*.h, *.cpp, *.obj, *.dfm) im Windows-Explorer markiert und in einen neuen Ordner kopiert.

    Die obj-Dateien sind nur temporäre Dateien die vom Compiler angelegt werden. Die brauchst du nicht mitkopieren. Ganz im Gegenteil, im neuen Projekt sollte die obj-Datei besser noch mal neu erstellt werden. Lösch mal die alte obj-Datei und schau ob der Fehler immer noch kommt.

    Wenn ja gibt es vermutlich irgendwo ungültige Zugriffe, zum Beispiel über zu hohe Werte in Group und Position. Benutzt den Debugger um die Ursache zu finden.

    bis bald
    akari



  • Danke für deine Antwort.

    Ich habe die *.obj jetzt mal gelöscht und das Projekt neu erstellt. Der Zugriffsfehler tritt immernoch auf.

    Ich habe im letzten Quellcode-Post einen Fehler gemacht: es heißt nicht Wert, sondern Vorlage (ich editiere das gleich noch).

    akari schrieb:

    Aus dem gezeigten Quellcode läßt sich für uns keine eindeutige Fehlerursache herauslesen.

    Das ist ja das Problem. Mehr Quellcode spielt da keine Rolle, weil mehr nicht passiert beim Erstellen (Instanziieren) des Formulars.

    Hier mal der gesamte Konstruktor des Formulars:

    __fastcall TFormXYZ::TFormXYZ(TComponent* Owner)
    	: TForm(Owner)
    {
    	this->ShowHint= false;
    	GrpIdx, UseLstLen, ComboBoxGroups->ItemIndex= 0;
    	MidValSelCnt= 0;
    	for(unsigned short i=0; i<18; i++)
    	{ ListBox1->Items->Add(PutEntry(0, i)); }
    }
    

    Da werden eigentlich nur noch Variablen / Eigenschaften initialisiert. Ansonsten ist da hauptsächlich die Schleife mit dem Funktionsaufruf. Wenn die Funktion das ERSTE Mal aufgerufen wird, tritt beim Verlassen der Zugriffsfehler auf (siehe mein Eröffnungs-post). Kann es sein, dass da eine Rückkehr-Adresse nicht gefunden wird? Wie kann beim Schliessen des Anweisungsblocks ( } ) eine Zugriffsverletzung auftreten??? 😕

    Edit: Ich habe oben zum Schluss geschrieben "es steht der gewünschte Wert in Eintrag" - das habe ich mit dem Debugger überprüft! Das Formular wird nicht erstellt und nicht angezeigt!!!



  • akari schrieb:

    Wenn ja gibt es vermutlich irgendwo ungültige Zugriffe, zum Beispiel über zu hohe Werte in Group und Position. Benutzt den Debugger um die Ursache zu finden.

    Was soll mir das eigentlich sagen? Ich habe den Konstruktor (mit der Schleife die den Funktionsaufruf macht) und alle Variablen gepostet. Daraus sollte ersichtlich sein, dass keine ungültigen Zugriffe stattfinden. Wie bereits gefragt:

    Worauf wird bei Abarbeitung von: } zugegriffen? Genau bei Abarbeitung dieses Befehls tritt die Verletzung auf, wie bereits gepostet.



  • Was soll denn diese Zeile hier eigentlich machen?

    GrpIdx, UseLstLen, ComboBoxGroups->ItemIndex= 0;
    

    Weiterhin

    akari schrieb:

    Benutzt den Debugger um die Ursache zu finden.

    Setze einen Brekpoint in den Konstruktor und schau dir deine variablen an.



  • Hallo

    Kolumbus schrieb:

    akari schrieb:

    Wenn ja gibt es vermutlich irgendwo ungültige Zugriffe, zum Beispiel über zu hohe Werte in Group und Position. Benutzt den Debugger um die Ursache zu finden.

    Was soll mir das eigentlich sagen? Ich habe den Konstruktor (mit der Schleife die den Funktionsaufruf macht) und alle Variablen gepostet. Daraus sollte ersichtlich sein, dass keine ungültigen Zugriffe stattfinden.

    Das war auch nur eine Möglichkeit. Zum Beispiel ist für uns nicht ersichtlich was genau in Vorlage steht, d.h. ob LastDelimiter überhaupt ein gültiges Ergebnis für Delete liefert.

    Worauf wird bei Abarbeitung von: } zugegriffen? Genau bei Abarbeitung dieses Befehls tritt die Verletzung auf, wie bereits gepostet.

    Insbesondere werden dort die Destruktoren aller lokalen statischen Instanzen aufgerufen.

    bis bald
    akari



  • Schreib ich eigentlich chinesisch?

    @Braunstein: Die von dir angefragte Zeile initialisiert Variablen, das habe ich bereits gepostet... Die Variablen werden korrekt initialsiert, das habe ich überprüft... Es ist völlig egal was diese Zeile macht, weil sie mit dem Fehler in keinerlei Zusammenhang steht... Die Variablen werden nämlich nicht gebraucht für die Schleife im Konstruktor oder die in der Schleife aufgerufenen Funktion!!!!

    @akari:

    akari schrieb:

    Zum Beispiel ist für uns nicht ersichtlich was genau in Vorlage steht, d.h. ob LastDelimiter überhaupt ein gültiges Ergebnis für Delete liefert.

    Ich habe bereits gepostet, dass der Inhalt von Eintrag nach Abarbeitung von

    return(Eintrag);
    

    STIMMT und der Fehler GANZ GENAU bei diesem Aufruf:

    }
    

    der Funktion auftritt (Siehe "// !!!" im Eröffnungs-Post). Was hat das dann noch mit LastDelimiter oder Delete zu tun?
    Edit: In Vorlage stehen AnsiStrings, die allesamt auf ~a enden.

    akari schrieb:

    Worauf wird bei Abarbeitung von: } zugegriffen? Genau bei Abarbeitung dieses Befehls tritt die Verletzung auf, wie bereits gepostet.

    Insbesondere werden dort die Destruktoren aller lokalen statischen Instanzen aufgerufen.

    Und die wären in meinem Fall? Edit2: Doch eigentlich nur die übergebenen Parameter oder?



  • Die von mir gezeigte Zeile initialisiert nur eine Variable, nämlich ComboBoxGroups->ItemIndex
    Die anderern werden nicht verändert.
    Hast du dir mal den Callstack angeschaut wenn die Exception kommt?



  • Kolumbus schrieb:

    Ich habe bereits gepostet, dass der Inhalt von Eintrag nach Abarbeitung von

    return(Eintrag);
    

    STIMMT und der Fehler GANZ GENAU bei diesem Aufruf:

    }
    

    der Funktion auftritt (Siehe "// !!!" im Eröffnungs-Post). Was hat das dann noch mit LastDelimiter oder Delete zu tun?
    Edit: In Vorlage stehen AnsiStrings, die allesamt auf ~a enden.

    Wir fragen nach was für uns nicht ersichtlich ist, aber aus unserer Erfahrung heraus am ehesten als Fehlerquelle in Betracht kommt. Insbesondere bei solchen mysteriösen, "kann gar nicht sein"-Fehlern ist es nämlich am besten alle als "sicher" geltende Annahmen zu überprüfen. Die Zeile wo die AccessViolation gemeldet wird ist dabei nur der Auslöser, der eigentliche Grund kann sehr wohl davor sein. Un ungültiger Code kann alle möglichen Konsequenzen hervorrufen.

    Und die wären in meinem Fall?

    Ich habe das nur als allgemeine Antwort auf deine allgemeine Frage eingeworfen. Ich kann in deinem Codeauszug von PutEntry keine lokalen Variablen sehen.

    Ich kann dir noch empfehlen alle Zeilen aus Konstruktor und PutEntry erstmal auszukommentieren und zu prüfen ob der Fehler noch kommt. Wenn nicht dann solange Zeilen wieder zu aktivieren bis der Fehler wieder kommt.

    bis bald
    akari



  • Entschuldigt meine Ungeduld.

    Braunstein schrieb:

    Die von mir gezeigte Zeile initialisiert nur eine Variable, nämlich ComboBoxGroups->ItemIndex
    Die anderern werden nicht verändert.

    Du hast natürlich Recht! Es stand immer nur zufällig 0 drin... So ists dann richtig:

    GrpIdx= 0, UseLstLen= 0, ComboBoxGroups->ItemIndex= 0;
    

    Braunstein schrieb:

    Hast du dir mal den Callstack angeschaut wenn die Exception kommt?

    Ähmm... wen bitte? Aufrufstapel? Noch nie gemacht... ich such gleich mal... Ok, hab nen ScreenShot - wo kann ich den öffentlich zugänglich machen, ohne mich lange anmelden zu müssen?

    akari schrieb:

    Ich kann dir noch empfehlen alle Zeilen aus Konstruktor und PutEntry erstmal auszukommentieren und zu prüfen ob der Fehler noch kommt. Wenn nicht dann solange Zeilen wieder zu aktivieren bis der Fehler wieder kommt.

    Wird sofort gemacht... Das Ergebnis:

    __fastcall TFormXYZ::TFormXYZ(TComponent* Owner)
    	: TForm(Owner)
    {
    	this->ShowHint= false;
    	GrpIdx= 0, UseLstLen= 0, ComboBoxGroups->ItemIndex= 0;
    	MidValSelCnt= 0;
    	for(int i=0; i<18; i++)
    	{
    		AnsiString Test= PutEntry(0, i);
    //		ListBox1->Items->Add(Test);      <===== hier haben wir die Zugriffsverletzung
    	}
    }
    

    Mit der Funktion hat das also nichts zu tun. Hilft das weiter?



  • Ich hatte jetzt noch die Idee, dass ich im Konstruktor noch nicht zuverlässig auf ListBox1 zugreifen kann, weil ich nicht weiß ob die Komponente schon erstellt wurde!?! Also hab ich die Schleife aus dem Konstruktor mal ins OnShow geschoben, aber die Zugriffsverletzung tritt trotzdem auf... 😞



  • Hallo

    Im Konstruktor von abgeleiteten Form-Klassen sind alle mit dem OI erstellte Komponenten vorhanden, die werden vom TForm-Konstruktor erstellt.

    OnShow ist übrigens keine Alternative zum Konstruktor, das wird erst aufgerufen wenn das Form überhaupt angezeigt wird, dann aber bei jedem Aufruf von Show().

    bis bald
    akari



  • Ok, dann bin ich immernoch nicht weiter. Habt ihr meinen letzten Post auf Seite 1 auch gelesen? Ich hatte 2x geantwortet...



  • Hier der CallStack, direkt nachdem der Zugriffsfehler auftrat und das Programm vom BCB angehalten wurde: Link



  • Wie man da sehen kann, wird der Fehler von MenuCfgRTClick verursacht. Also schau da mal rein.



  • Die Methode MenuCfgRTClick sieht so aus:

    void __fastcall TFormMain::MenuCfgRTClick(TObject *Sender)
    {
    	TFormRTCfg *FrmRTCfg= new TFormRTCfg(Application);
    	FrmRTCfg->ShowModal();
    	delete(FrmRTCfg);
    }
    

    Edit: Selbst wenn ich das Formular beim Programmstart erzeugen lassen und dann nur mit ShowModal() anzeige wenn man auf den Button klickt, bekomme ich eine Zugriffsverletzung...
    Ich gebs auf! Ich mach das Formular am Montag nochmal neu für das neue Projekt... Ist zwar n Haufen Fummelei, aber wenn ich ewig nach nem mysteriösem Fehler suche, komm ich auch nicht weiter.
    Ich denk mir meinen Teil dazu - zB zum Thema "Wiederverwendbarkeit von Objekten"...



  • Den einzigen Fehler, den ich hier sehe, ist, dass Du das Formular wieder löschst, obwohl Du die Application als Eigentüber angibst. Also entweder löschen weglassen, oder (mE besser) keinen Eigentümer angeben.

    Sollte aber mit dem Problem selbst nichts zu tun haben...

    Hast Du einfach mal die ListBox vom Furmular gelöscht und neu eingefügt?



  • ersetze doch mal das hier

    delete(FrmRTCfg);
    

    durch das hier

    delete FrmRTCfg;
    

    Dann schau mal rein ob im Konstruktor von TFormRTCfg noch ein Ei sein könnte.



  • Joe_M. schrieb:

    Den einzigen Fehler, den ich hier sehe, ist, dass Du das Formular wieder löschst, obwohl Du die Application als Eigentüber angibst. Also entweder löschen weglassen, oder (mE besser) keinen Eigentümer angeben.

    Verstehe ich nicht... Ich muss doch einen Eigentümer angeben!?! Folgende Varianten erzeugen erwartungsgemäß eine Fehlermeldung:

    TFormRTCfg *FrmRTCfg= new TFormRTCfg();   // Variante 1 ohne Owner
    TFormRTCfg *FrmRTCfg= new TFormRTCfg;     // Variante 2 ohne Owner
    

    Und zwar erzeugen beide Varianten diese Fehlermeldung:

    [C++Fehler] Main.cpp(92): Could not find a match for 'TFormRTCfg::TFormRTCfg()'.

    Also bitte Joe_M, schreib mir noch, wie ich das Formular ohne Owner instanziiere und warum es falsch ist mit Application als Owner. 😕

    Joe_M. schrieb:

    Sollte aber mit dem Problem selbst nichts zu tun haben...

    Hast Du einfach mal die ListBox vom Furmular gelöscht und neu eingefügt?

    Das habe ich jetzt mal gemacht - keine Veränderung! Ich habe der ListBox sogar einen neuen Namen verpasst.

    Braunstein schrieb:

    ersetze doch mal das hier

    delete(FrmRTCfg);
    

    durch das hier

    delete FrmRTCfg;
    

    Was soll die Ersetzung bewirken?

    Braunstein schrieb:

    Dann schau mal rein ob im Konstruktor von TFormRTCfg noch ein Ei sein könnte.

    Den Konstruktor haben wir hier doch schon durchgekaut...

    __fastcall TFormRTCfg::TFormRTCfg(TComponent* Owner)
    	: TForm(Owner)
    {
    	GrpIdx= 0, UseLstLen= 0, ComboBoxGroups->ItemIndex= 0;
    	MidValSelCnt= 0;
    	AnsiString TmpStr;
    	for(int Idx=0; Idx<18; Idx++)
    	{
    		TmpStr= PutEntry(0, Idx);
    		LstBxGet->Items->Add(TmpStr);   // Hier entsteht die Zugriffsverletzung
    	}
    }
    


  • Kolumbus schrieb:

    Joe_M. schrieb:

    Den einzigen Fehler, den ich hier sehe, ist, dass Du das Formular wieder löschst, obwohl Du die Application als Eigentüber angibst. Also entweder löschen weglassen, oder (mE besser) keinen Eigentümer angeben.

    Verstehe ich nicht... Ich muss doch einen Eigentümer angeben!?! Folgende Varianten erzeugen erwartungsgemäß eine Fehlermeldung:

    TFormRTCfg *FrmRTCfg= new TFormRTCfg(0);   // korrekte Variante ohne Owner
    

    Braunstein schrieb:

    ersetze doch mal das hier

    delete(FrmRTCfg);
    

    durch das hier

    delete FrmRTCfg;
    

    Was soll die Ersetzung bewirken?

    Das die überflüssigen Klammern verschwinden. delete ist ein Operator, keine Funktion.

    Aber beide Sachen sind nur Schönheitskorrekturen und haben mit der eigentlichen Access Violation nichts zu tun.

    bis bald
    akari


Anmelden zum Antworten