Der Destruktor wird nicht aufgerufen
-
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
-
Da der Aufbau der Hashtable (und ihre Art der Speicherverwaltung) Betriebsgeheimnis von Fox sind, kann wohl nur er dazu Stellung nehmen.
Aber von der Logik her sollte die Hashtable selber dafür zuständig sein, ihre eigenen Iteratoren aufzuräumen (und ich würde vermutlich den Iterator nicht per Zeiger nach außen übergeben, sondern als Wert).
-
Ich arbeite selbst erst seit einiger zeit mit C++ (vorher mit Java) und lerne dabei die Sprache. So wie der Container entworfen wurde, muss man gut aufpassen was man macht. Der Container im Code erzeugt einen Iterator welcher die einzelnen Einträge (Items) durchläuft und Zeiger auf diese Zurückgibt. Der Iterator ist dabei nicht existenzabhängig von dem Container daher muss dieser von Hand entfernt werden. Das ganze ist zwar unsicher und kann zu ne Menge Fehlern führen ist aber so weit ich das sehe schnell, als wenn ich statt dessen mit Kopien arbeiten würde. Da das ganze gekapselt wird so, dass man auf diese unterste Eben nicht zugreifen kann ist es in Ordnung so.
Hoffe, dass ich die Frage ausreichen beantwortet habe.
mfg.
-
Das argument verstehe ich nicht,
was haben die Kopien mit der Existenzunabhängigkeit (?!)
mit dem Objekt was iteriert werden soll mit hoher Fehleranfälligkeit zu tun ?(Btw.: Man könnte das auch als const zurück geben)
-
Und ich fürchte, die Java-Herkunft sieht man deinen Programmen auch an
In C++ sollte items() besser keinen Pointer auf einen Iterator übergeben, sondern einen Wert. Der ist dann auch existenzunabhängig von deinem Container - muß aber nicht mehr von Hand beseitigt werden.