Der Destruktor wird nicht aufgerufen
-
Nur mal zur Orientierung: Ist 'OGLSchriftart' die Basisklasse oder die abgeleitete Klasse? Wenn ersteres, hängst du genau an dem Problem, das Simon oben beschrieben hat - da der Destruktor auf Basis des statischen Typs ausgewählt wird, erwischst du nur den Basis-Dtor, wenn du über einen Basis-Zeiger zugreifst.
-
Nein, das ist der 2 Fall:
class SpeicherbaresObjekt { protected: string name; public: SpeicherbaresObjekt(string& name) {this->name = name;} virtual ~SpeicherbaresObjekt() {} // nun jetzt auch virtuell string _name() {return name;} }; class OGLSchriftart: public SpeicherbaresObjekt { //... public: //... virtual ~OGLSchriftart(); // nun jetzt auch virtuell //... }; OGLSchriftart::~OGLSchriftart() { // der hier stehende Code wird nicht aufgeruffen }
Wie gesagt ist das eben, das dubiose
mfg.
-
Also ich denke, dass in dem Fall der Zeiger, auf den Du beim delete übergibst, tatsächlich auf eine Basisklasseninstanz zeigt.
Entweder wirfst Du bereits ein "SpeicherbaresObjekt" in den Container oder der kopiert irgendwo doch implizit in ein solches....
Schonmal den CopyCtor, operator=() und mögliche Konversionsoperatoren "privatisiert" ?Bei mir funktioniert jedenfalls auch der Umweg über "Basisklassen-Referenzen" prima:
class BitteAbleiten { public: virtual ~BitteAbleiten() { std::cout << "~BitteAbleiten\n"; } }; class GutAbgeleitet : public BitteAbleiten { public: ~GutAbgeleitet() { std::cout << "~GutAbgeleitet\n"; } }; void deleteMe(BitteAbleiten* p) { delete p; } void doIt(BitteAbleiten& b) { deleteMe(&b); } int main() { doIt(*new GutAbgeleitet); return 0; }
Ergebnis wie erwartet:
~GutAbgeleitet
~BitteAbleitenEin wenig überrascht mich, dass der Iterator (der Container auch ?) bei Dir für den Typen OGLSchriftart (also den abgeleiteten) instantiiert wird; eigentlich kenne ich das nur für Basistypen, wenn man Polymorphie nutzen will.... aber dazu weiß ich zuwenig von Deinem Container.
Gruß,
Simon2.
-
Nein, eben nicht wenn ich im Debugmodus bin und denn Code Schritt für Schritt durchgehe und mir die Variablen anschaue so zeigt oglsa auf eine Instanz von OGLSchriftart. In dem Programm habe ich noch einige andere Klassen die vom SpeicherbarenObekt erben und deren Destruktor auch aufgerufen wird und auch wenn es die Basisklasse währe so müsste der Destruktor der Abgeleiteten Klasse ebenfalls aufgerufen werden da ich dieses als virtual deklariert habe. Es ist halt die einzige Klasse die spinnt oder ich.
Schonmal den CopyCtor, operator=() und mögliche Konversionsoperatoren "privatisiert" ?
Nein.
Ein wenig überrascht mich, dass der Iterator (der Container auch ?) bei Dir für den Typen OGLSchriftart (also den abgeleiteten) instantiiert wird; eigentlich kenne ich das nur für Basistypen, wenn man Polymorphie nutzen will.... aber dazu weiß ich zuwenig von Deinem Container.
Ich iteriere den Container nur um die Instanzen zu entfernen.
mfg.
-
9taleFox schrieb:
...auch wenn es die Basisklasse währe so müsste der Destruktor der Abgeleiteten Klasse ebenfalls aufgerufen werden da ich dieses als virtual deklariert habe...
Ich dachte da an so etwas (vgl. obiges Beispiel):
int main() { BitteAbleiten b = *new GutAbgeleitet; // nutzt CpyCtor doIt(b); b = *new GutAbgeleitet; // nutzt operator=() doIt(b); return 0; }
oder noch unauffälliger:
void doIt(BitteAbleiten b) { // Versehentlich call-by-value deleteMe(&b); }
Sowas kann einem recht schnell und unbemerkt passieren.
Solchen "Kopierfallen" kommt man mit privatisiertenCpyCtor, operator=(), Konversionsoperatoren und "explicit" auf die Schliche.....
In all diesen Fällen zeigt letztlich der "zu deletende Zeiger" auf ein Basisklassenobjekt ... und da wird natürlich auch der BasisklassenDtor aufgerufen (wurde bei dem speziellen Objekt ja nicht overridden).
(hier meine ich "Zeiger auf ein Basisklassenobjekt" und NICHT "Basisklassenzeiger auf ein Objekt")Ganz zu schweigen davon, dass man dabei unbemerkt ein delete auf ein Stackobjekt macht, was gaaaanz Pfuibäh ist .... aber verzeihlich, weil ja ein Fehler.
Gruß,
Simon2.
-
Wenn es der Fall währe müsste es bei jeder anderen Klasse genau so en Problem geben, aber vielleicht sehe ich das Problem einfach nicht, hier ist der Code ... falls jemand zu viel zeit über hat :).
Entwiklungsumgebung MSVC++ 2005 EE
mfg
-
Hopps,
das ist aber ein Brocken für "mal eben" (zumal ich keine MSVC++ 2005 EE) habe ....
Du bist aber vermutlich sicher, dass der Dtor nicht aufgerufen wird (so mit Ausgabe ausprobiert und so) ?!?
Gruß,
Simon2.
-
Beim Compilieren erhälst Du eine Warnmeldung, das der Typ OLGSchriftArt nicht bekannt ist. Includiere den Header, damit der Compiler weiß wie die Klasse aussieht.
Warnung 15 warning C4150: Löschen eines Zeigers auf den nicht definierten Typ 'OGLSchriftart'. Destruktor wurde nicht aufgerufen. c:\dokumente und einstellungen\mroth\desktop\openglwindow_test2\openglwindow_test2\oglbild.cpp 161
Warnungen sind zum lesen da, nicht zum Ignorieren
-
OK, ich habe einen Verdacht, galube das du recht haben könntest bin mir aber noch nicht sicher. Die Warnung wurde bei mir nicht angezeigt, aber das liegt wohl an dem Container.
-
Ich bin mir schon sicher
-
Knuddlbaer schrieb:
Beim Compilieren erhälst Du eine Warnmeldung, das der Typ OLGSchriftArt nicht bekannt ist. Includiere den Header, damit der Compiler weiß wie die Klasse aussieht.
Warnung 15 warning C4150: Löschen eines Zeigers auf den nicht definierten Typ 'OGLSchriftart'. Destruktor wurde nicht aufgerufen. c:\dokumente und einstellungen\mroth\desktop\openglwindow_test2\openglwindow_test2\oglbild.cpp 161
Warnungen sind zum lesen da, nicht zum Ignorieren
Das ist eine Warnung ???
Ich hätte das als Grund für einen echten Fehler gehalten....Gruß,
Simon2.
P.S.: Mich hatte schon ein wenig irritiert, dass in Bild plötzlich nochmal Schriftart-Verwaltung auftauchte, aber meine Energie reichte nicht weiter....
-
OK das habe ich ganz übersehen, wenn da nur
class OGLSchriftart;
steht, sollte man sich eigentlich nicht wundern, wenn man zulange davor sitzt sieht man irgendwann überhaut nichts mehr, ich danke euch vielmals!!!
P.S.: Mich hatte schon ein wenig irritiert, dass in Bild plötzlich nochmal Schriftart-Verwaltung auftauchte, aber meine Energie reichte nicht weiter....
Wenn die Textur nicht mehr existiert auf der, die Schriftart definiert ist, sollte auch die Schriftart nicht mehr geben, war der Gedanke.
mfg.
-
9taleFox schrieb:
...
Wenn die Textur nicht mehr existiert auf der, die Schriftart definiert ist, sollte auch die Schriftart nicht mehr geben, war der Gedanke.mfg.
Klingt logisch !
Aber mal eine Frage: Wie kommt es, dass Du die Warning nicht gesehen hast ? Hast Du die abgeklemmt ?
Gruß,
Simon2.
-
Wenn man ständig mit warnungen wie,
warning C4996: 'fopen' wurde als veraltet deklariert oder 'Initialisierung': Konvertierung von 'double' in 'int', möglicher Datenverlust
geplagt wird ,die ersteinmal nicht so wichtig sind, neigt man dazu diese zu ignorieren, tja und schwups und man ignoriert welche die wichtig sind, also praktisch nicht angezeigt ;).
mfg
-
Kann ich einerseits verstehen, andererseits sehen wir jetzt gerade ein Beispiel, wie wichtig sie sein können.
Vielleicht solltest Du zukünftig gezielt Warnungen (evtl. nur bei bestimmten Modulen und nur bestimmte Warnungsnummern) abklemmen....Zumindestens, wenn Du wieder mal dem Compiler Fehlverhalten nachweisen willst, lohnt sich vielleicht doch ein Blick in die Warnings
Aber nun gut: Hinterher ist man immer schlauer !
Gruß,
Simon2.
P.S.: Die, die Du da als Beispiel angeführt hast, würden mich ja schon zum Nachdenken bringen (es sei denn, sie kommen aus "Fremdsoftware") ...
-
Normaler weise schaue ich auch über die Warnungen, aber erst vor der Fertigstellung, da sieht man, dass es keine gute Einstellung ist, tja da hast du schon recht :).
P.S.: Die, die Du da als Beispiel angeführt hast, würden mich ja schon zum Nachdenken bringen (es sei denn, sie kommen aus "Fremdsoftware") ...
Teils, teils, bei warning C4996: 'fopen' wurde als veraltet deklariert kann man einfach mal wegsehen (es seiden es könnte Fehler verursachen von denen ich nichts ahne) und das 'Initialisierung': Konvertierung von 'double' in 'int', möglicher Datenverlust sollte in einem fertiggestellten Code nicht auftauchen.
mfg.
-
Solange man sich nicht sicher ist, was da passiert, sollte man mindestens ein schlechtes gefühl haben wenn man die Warnung ignoriert
Egal, fehler gefunden und was gelernt
-
Naja, die 4996 und verwandte liefert auch nur der VC++ 8.0, weil Microsoft mal eben meinte die als veraltet deklarieren zu dürfen (was imho durch keinen Standard gedeckt ist).
Aber diese Warnings kann man in den Projektoptionen ganz sicher abschalten
-
LordJaxom schrieb:
Naja, die 4996 und verwandte liefert auch nur der VC++ 8.0, weil Microsoft mal eben meinte die als veraltet deklarieren zu dürfen (was imho durch keinen Standard gedeckt ist).
Aber diese Warnings kann man in den Projektoptionen ganz sicher abschalten
Wenn mans über die project-properties macht muss man den Warning-Level runterdrehen, und das mache zumindest ich nicht gerne. Aber man kann folgende Macros definieren bevor man irgendwelche Headers inkludiert, dann hat man auch Ruhe:
#define _AFX_SECURE_NO_DEPRECATE #define _ATL_SECURE_NO_DEPRECATE #define _CRT_SECURE_NO_DEPRECATE #define _SCL_SECURE_NO_DEPRECATE
-
Hat zwar nur indirekt was mit dem Thema zu tun aber der vorher gepostete Code von 9taleFox ist mir nicht ganz klar bzw. missverständlich und würde mich freuen wenn mich da jemand aufkären kann.
if (nackomen_Schriftart != NULL) { HashtableIterator<OGLSchriftart>* hti = nackomen_Schriftart->items(); while (hti->hasMore()) { OGLSchriftart* oglsa = hti->getNext(); delete oglsa; } delete hti; // <-- Diese Stelle delete nackomen_Schriftart; }
Trifft folgendes nicht zu?
1. "hti" wird automatisch gelöscht wenn es von "nackomen_Schriftart" ein Member ist.
2. "hti" (höchstwahrscheinlich) ein Member ist da es nicht viel Sinn ergeben würde eine Kopie von einem "HashtableIterator<OGLSchriftart>" zu erstellen welche die Orginalzeiger auf die "OGLSchriftart"(en) enthält.
3. Falls 1 und 2 zutreffen, würde das Programm nicht in ein undefiniertes Verhalten abgleiten dadurch das es etwas löschen will was nicht mehr existiert. Sprich das "hti" welcher Member von "nackomen_Schriftart" ist kann in dessen Zerstörung nicht mehr gelöscht werden.
4. Würde folgender Code den Annahmen entgegenwirken. Falls nicht, warum?if (nackomen_Schriftart != NULL) { HashtableIterator<OGLSchriftart>* oglSchriften = nackomen_Schriftart->items(); while (oglSchriften->hasMore())) { delete oglSchriften->getNext(); } delete nackomen_Schriftart; }
Entschuldigung für dieses ganze Annahmengerede aber momentan lerne ich C++ eher theoretischer Natur, also mit einem Buch bei der Fahrt von bzw. zu der Arbeit. Zum praktischen Einsatzt bin ich eigentlich noch nicht wirklich gekommen mal von ein paar kleinen Testprogrammen abgesehen. Dennoch würde ich trotzdem gerne was dazulernen