delete im Destruktor
-
ich habe in einer klasse ein DynamicArray für TImage und TLabel.
durch Paint(); reserviere ich speicher über new und mit Clear(); gebe ich ihn wider mit delete frei.
wenn ich das von hand aufrufe, geht das super
aber wenn ich die clearfunktion im Destruktor aufrufe, kommt ein Fehler "EAccessViolation"
also habe ich probleme mit dem speicherbereich.
da es aber sonst geht, zum freigeben, denke ich das liegt im zusammenhang mit dem Destruktor__fastcall TElTecGraph::~TElTecGraph() { // anfang Clear-Funktion if (bPaint) { for (int iCounter = imgSector.Length-1; iCounter >=0; iCounter--) { delete imgSector[iCounter]; if (iCounter != 0) delete labSector[iCounter]; imgSector.Length--; labSector.Length--; } } // ende Clearfunktion delete strlSectors; delete picSector; delete picSpray; }habe ich da irgendwie einen groben fehler drin?
-
Hallo
Debuggen und schauen, welches delete genau die Exception wirft.
Dein Codeausschnitt ist wohl nicht ausreichend.bis bald
akari
-
Hallo,
Warum verringerst du die Größe deines Arrays in der Schleife? Du bist doch im Destruktor. Das Array ist danach ohnehin nicht mehr da.
-
mein problem liegt eben, dass die funktion eigentlich funktioniert, nur nicht im Destruktor.
ich versuche das mal zu veranschaulichen ohne seitenweise code..void __fastcall TElTecGraph::Clear() { /* löschen der Images und Labels */ bPaint = false; for (int iCounter = imgSector.Length-1; iCounter >=0; iCounter--) { delete imgSector[iCounter]; if (iCounter != 0) // labSector[0] wird nie gebraucht delete labSector[iCounter]; imgSector.Length--; labSector.Length--; } } //--------------------------------------------------------------------------- bool __fastcall TElTecGraph::Paint() { bPaint = true; imgSector.Length = 1; labSector.Length = 1; ... imgSector[0] = new TImage(); ... for (int iCounter = 1; iCounter <= strlSectors->Count; iCounter++) //strlSectors enthält bezeichnung für die images { imgSector.Length++; imgSector[iCounter] = new TImage(); ... labSector.Length++; labSector[iCounter] = new TLAbel(); ... } return (true); }die 2 Funktionen laufen super..
ich kann über 2 Buttons zuerst Paint() aufrufen(Image und Label werden angezeigt)
und über Clear() (alles wieder löschen/speicher freigeben)
läuft super
jetzt will ich im Destruktor noch testen, ob Speicher reserviert ist (bPaint) und fals ja, Clear aufrufen.
__fastcall TElTecGraph::~TElTecGraph() { if (bPaint) Clear(); delete strlSectors; // die 3 delete laufen sauber, da wenn bPaint == false kein error kommt delete picSector; delete picSpray; }sobald aber bPaint true ist löst es den "EAccessViolation" aus..!?
-
Wo rufst Du den Destruktor auf?
Was übergibst Du denn im Konstruktor bei der Erstellung der TImage- bzw. TLabel-Objekte?
Wenn Du das so machst:TLabel* lbl = new TLabel(Application);Dann ist Application für das Freigeben verantwortlich. Wenn Du Dein Programm beendest (oder vielleicht auch nur das
Formular schließt) und Application war schneller, dann versuchst Du einen ungültigen Zeiger zu löschen.Gruß,
Alexander
-
Der Owner sollte hier nicht gestzt sein (also NULL).
Dann sind die Schleifen zu umständlich formuliert. Wenn du die Größe des Array kennst, warum setzt du sie dann nicht gleich (so auch beim Clear()).
Was passiert, wenn Paint zweimal hintereinander aufgerufen wird? Also teste hier lieber bPaint ab. Diese Variable kannst du zu Not auch weglassen und statt dessen die Länge deines DynamicArrays verwenden.
-
irgend etwas in diese richtung dachte ich mir @ alex
also ich rufe die Konstruktoren so auf
imgSector[0] = new TImage(wcImgParent->Owner); labSector[iCounter] = new TLabel(wcImgParent->Owner);TWinControl *wcImgParentdort kann man den Parent für die Images und Labels festlegen.. zB GroubBox1, etc..
ist das das selbe wie mit Application?
-
Braunstein schrieb:
Dann sind die Schleifen zu umständlich formuliert. Wenn du die Größe des Array kennst, warum setzt du sie dann nicht gleich (so auch beim Clear()).
die ändern ja immer.. ich lese aus einer StringList aus(pro eintrag 1 image+label)
Braunstein schrieb:
Was passiert, wenn Paint zweimal hintereinander aufgerufen wird? Also teste hier lieber bPaint ab. Diese Variable kannst du zu Not auch weglassen und statt dessen die Länge deines DynamicArrays verwenden.
die abfrage habe ich schon drin.. wollte den code möglichst einfach halten und die sache nicht unnötig komplizieren

-
BigNeal schrieb:
ist das das selbe wie mit Application?
Durch einen Blick in die Hilfe wird sich Dir die Bedeutung von Owner erschließen.
Dann wirst Du auch erkennen, dass es im Prinzip egal ist, ob Du Application oder irgendein Formular oder sonstwas
übergibst.
Braunstein hat schon recht: Am besten Du übergibst null, dann kümmert sich niemand um das Freigeben; d.h. dass Du
das dann machen musst.Gruß,
Alexander
-
die ändern ja immer.. ich lese aus einer StringList aus(pro eintrag 1 image+label)
Du kennst doch aber die Länge der StringList.
Ich meine das so:bool __fastcall TElTecGraph::Paint() { imgSector.Length = strlSectors->Count+1; labSector.Length = strlSectors->Count+1; ... imgSector[0] = new TImage(); ... for (int iCounter = 1; iCounter <= strlSectors->Count; iCounter++) //strlSectors enthält bezeichnung für die images { imgSector[iCounter] = new TImage(NULL); ... labSector[iCounter] = new TLAbel(NULL); ... } bPaint = true; return (true); }
-
Wofür brauchst Du eigentlich die Stringliste?
Es würde doch genügen, ein dynamisches Array zu verwenden, das Objekte enthält, die wiederum Objekte von Labeln und
Images enthalten.Beispiel:
class TImageLabel { public: TImageLabel(); ~TImageLabel(); __property TLabel* Label = {read=FLabel}; __property TImage* Image = {read=FImage}; private: TLabel* FLabel; TImage* FImage; };Wenn Du eine Klasse erstellst, die von TObject erbt, kannst Du die Objekte sogar direkt in der Stringliste speichern.
Ein solche Klasse hat den Vorteil, dass sie sich um das Erstellen/Freigeben kümmert und außerdem ganz leicht erweitert
werden kann ohne an x Stellen im Code zu ändern.Gruß,
Alexander
-
ok, gebe zu.. obwohl es nciht viel anderst ist, sieht es etwas hübscher aus

habe jetzt auf TLabel(NULL) und TImage(NULL) geändert..
funktioniert leider immernochnicht.. der selbe error wird beim beenden mit bPaint == true ausgelöst.
wenn ich die BCB-Hilfe richtig verstanden habe, übergebe ich mit dem Parentwert auch wieder den "Owner" wobei ich weider gleich weit bin.
ich habe das ganze wieder zurückgestellt, so wie ich es hatte und einfach den Clear() aufruf im Destruktor weggelassen, da der speicher ja automatisch freigegeben wird.thx allen für die hilfe und fürs mitdenken

@ alex
ich will mit den TImage die zonen eines Aggregates darstellen. Mit den Label bezeichne ich die HeizbänderNr/FühlerNr. so muss man zB nur die werte "1", "2", "3", "4" in die Stringlist schreiben um die fühler anzuzeigen mit dem entsprechendem bild dahinter (das ganze verreinfacht!)
-
wenn ich die BCB-Hilfe richtig verstanden habe, übergebe ich mit dem Parentwert auch wieder den "Owner"
Dann hast du die Hilfe nicht richtig verstanden. Der Parent ist die Komponente auf welcher deine Komponente angezeigt wird. Der Owner ist für das Löschen zuständig. Die beiden sind unabhängig.
Ich würde dein Programm lieber nochmal debuggen (Breakpoint im Destruktor setzen o.ä.) und schauen wo es hängenbleibt. Deine jetzige Lösung ist sehr unschön.
-
BCB-Hilfe schrieb:
Hinweis: Die in TControl deklarierte Eigenschaft Parent ähnelt der Eigenschaft Owner von TComponent darin, daß die hier angegebenen Objekte für das Freigeben des Steuerelements zuständig sind.
also ich verstehe das so, dass das übergebene Objekt über Parent für das Freigeben des Images zuständig ist.
oder was verstehe ich falsch?
-
BigNeal schrieb:
wenn ich die BCB-Hilfe richtig verstanden habe, übergebe ich mit dem Parentwert auch wieder den "Owner"
Die Hilfe ist da ein bisschen unschön formuliert.
Du kannst das aber ganz leicht selbst ausprobieren. Neue Anwendung und dann in FormShow:TLabel* label = new TLabel(Application); label->Parent = this; label->AutoSize = true; label->Caption = "Owner:" + label->Owner->Name + " - Parent: " + label->Parent->Name;Im Grunde hast Du jetzt nicht das Problem behoben, sondern lediglich durch Rumprobieren einen Zustand gefunden,
der zu funktionieren scheint. Andrew Hunt und David Thomas nennen das in ihrem Buch "Der pragmatische Programmierer"
"Programmieren mit dem Zufall".Gruß,
Alexander
-
Bei mir steht in der Hilfe etwas anderes.
Note: Don't confuse the Parent property declared in TControl with the Owner property declared in TComponent. The Parent of a control is always a windowed control that visually contains the control, and which is responsible for writing the control to a stream when the form is saved. The Owner of a component is the component that was passed as a parameter in the constructor and that controls when the component is freed.
-
Braunstein schrieb:
Bei mir steht in der Hilfe etwas anderes.
Die Deutsche Übersetzung ist offensichtlich missglückt.
Gruß,
Alexander
-
Alexander Kempf schrieb:
Im Grunde hast Du jetzt nicht das Problem behoben, sondern lediglich durch Rumprobieren einen Zustand gefunden,
der zu funktionieren scheint. Andrew Hunt und David Thomas nennen das in ihrem Buch "Der pragmatische Programmierer"
"Programmieren mit dem Zufall".Ich habe lediglich noch nicht gewusst, dass Owner den Speicher freigibt und somit habe ich nochmals versucht den speicher freizugeben. wenn nicht allwissend sein mich in diese katergorie steckt, dan werde ich wohl noch seeeeeehr lange dort rein gehören

-
BigNeal schrieb:
Ich habe lediglich noch nicht gewusst, dass Owner den Speicher freigibt und somit habe ich nochmals versucht den speicher freizugeben.
BigNeal schrieb:
habe jetzt auf TLabel(NULL) und TImage(NULL) geändert..
funktioniert leider immernochnicht.. der selbe error wird beim beenden mit bPaint == true ausgelöst.Klingt für mich etwas widersprüchlich und nicht so, als ob Du den Fehler tatsächlich gefunden hast.
Mit allwissend hat das nichts zu tun, sondern damit, ob man einen Fehler tatsächlich beheben kann, also begriffen
hat, wo der Fehler liegt, oder nur solange blind irgendwas im Code umstellt, bis der Fehler nicht mehr auftaucht.
Das eine ist "Verstehen", das zweite "Hoffen".Gruß,
Alexander
-
ich habe den Fehler (noch) nicht gefunden, bei der variante, die mir hier vorgeschlagen wurde, mit der übergabe NULL.
bei meiner Variante mit Owner als übergabe, hat sich die Erromeldung ja geklährt.