Der Destruktor wird nicht aufgerufen



  • 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.



  • 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 ?

    Ok, da habe ich mich wohl wieder nicht so gut ausgedrückt. Die Hashtable erzeugt einen Iterator, gibt diesen zurück und hat danach keine Kenntnis mehr davon und sorgt sich nicht mehr dafür, dass es freigegeben wird. Also ist der Iterator nicht existenzabhängig von der Hashtable. Der Iterator gibt beim durchlaufen die Referenzen auf die Items zurück. Wen man nun einen Item löscht, besitzt die Hashtable Referenz auf ein nicht mehr existierendes Objekt, was zu Fehlern führen kann. Und denn noch muss, dass möglich sein. Und Kopien der Items sind unerwünscht.

    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.

    Das könnte man echt machen, das würde dann dem entsprechen:

    HashtableIterator<OGLSchriftart> hti = *nackomen_Schriftart->items();
    

    oder? Und was passiert aber da genau, wo wird dann der Iterator erzeugt? Im Heap? Und hält hti auch die Instanz die erzeugt wurde oder wird diese Kopiert und hti kennt dann die Kopie?

    mfg.



  • Das könnte man echt machen, das würde dann dem entsprechen:

    HashtableIterator<OGLSchriftart> hti = *nackomen_Schriftart->items();
    

    oder? Und was passiert aber da genau, wo wird dann der Iterator erzeugt? Im Heap? Und hält hti auch die Instanz die erzeugt wurde oder wird diese Kopiert und hti kennt dann die Kopie?

    Ok das ist schwachsinnig (weil Speicher verschwendung und Kopie), aber wenn man mit Werten arbeiten würde, so würde man zwangsläufig auch mit Kopien arbeiten, was ich aber vermeiden möchte.



  • Nun schieb die Schuld für den groben Designfehler nicht auf Kopien, Du kannst auch nen const iterator zurück geben.



  • Designfehler 🙂 , war erwünscht.
    Es wird hier nirgends die Schuld auf etwas geschoben, die Kopien waren von vornherein nicht erwünscht das ist alles.
    Und was meinst du mit const, was für einen Vorteil hat es?

    mfg.



  • 9taleFox schrieb:

    Das könnte man echt machen, das würde dann dem entsprechen:

    HashtableIterator<OGLSchriftart> hti = *nackomen_Schriftart->items();
    

    oder?

    Fast - aber besser wäre es, die Methode items() deiner Hashtable anzupassen, daß sie keinen Heap-Speicher anlegt.
    aus

    HashtableIterator<T>* items()
    {
      HashtableIterator<T> it = new HashtableIteator<T>;
      ...
      *it = ...;
      return it;
    }
    

    wird

    HashtableIterator<T> items()
    {
      HashtableIterator<T> it;
      ...
      it = ...;
      return it;
    }
    

    (wichtig: keine Pointer mehr - und keine new-Aufrufe. Dadurch wird der Iterator durch den Stack durchgereicht (und irgendwann automatisch beseitigt).



  • irgendwo in diesem forum stand, daß man c und c++ nicht mischen soll,
    fopen ist c, ifstream c++,
    wenn man das beachtet bekommt man generell keine warnungen(weil man fast in jeder ide unter projekteinstellungen angeben kann ob man ein c oder c++ programm erstellt).!



  • (wichtig: keine Pointer mehr - und keine new-Aufrufe. Dadurch wird der Iterator durch den Stack durchgereicht (und irgendwann automatisch beseitigt).

    Ja so würde das gehen, aber wie schon erwähnt würde die Instanz des öfteren kopiert und gelöscht werden.
    Bespiel:

    HashtableIterator<T> Hashtable<T>::items() 
    { 
      HashtableIterator<T> it; // erste Instanz von HashtableIterator<T> wird erzeugt
      ... 
      return it; // erste I. wird kopiert, somit haben wir eine zweite, und die erste wird gelöscht
    }
    
    ...
    HashtableIterator<T> it = hashtable->items(); // so hat it die Kopie der ersten Instanz
    …
    

    somit hat man einmal kopieren und einmal löschen müssen, und das habe ich mit dem kopieren gemeint, was wir eben vermeiden wollten.

    rgendwo in diesem forum stand, daß man c und c++ nicht mischen soll,
    fopen ist c, ifstream c++,
    wenn man das beachtet bekommt man generell keine warnungen(weil man fast in jeder ide unter projekteinstellungen angeben kann ob man ein c oder c++ programm erstellt).!

    Aha, werde mir mal anschauen.

    mfg.


Anmelden zum Antworten