Gültigkeit von Zeigern prüfen?



  • Über add(MeineSchnittstelle)* bzw. delete(MeineSchnittstelle)* möchte ich die Liste verändern. Aber wie finde ich heraus, das sich jemand angemeldet hat mit add(), dann aber ohne delete() schon wieder verschwunden ist?
    delete() und MeineSchnittstelle* ptr = NULL sind dann ähnlich aufwendig.



  • Über add(MeineSchnittstelle*) bzw. delete(MeineSchnittstelle*) möchte ich die Liste verändern. Aber wie finde ich heraus, das sich jemand angemeldet hat mit add(), dann aber ohne delete() schon wieder verschwunden ist?

    nachträglich kannst dud as nicht mehr

    aber es gibt 2 möglichkeiten,das zu verhindern:

    1. wenn MeineSchnittstelle nach dem delete(...) eh gekillt werden würde, so könnte sich doch prinzipiell der dtor drum kümmern...

    2. schreib in die doku: you have to call delete, else there will be undefined behaviour.



  • Danke. 🙂

    Ich hatte gerade einiges über Smartpointer gelesen und dachte: vielleicht gibt's ja dafür auch was .. 😃

    Dann bleibt nur der 2.Vorschlag. Hab eine Klasse, die Daten in eine Datei schreibt bzw. liest, und da können sich alle möglichen Klassen registrieren, die was zum Schreiben/Lesen haben.



  • Bin mit der Lösung nicht zufrieden! Muss doch noch einen anderen Weg geben, als es dem Nutzer zu überlassen .. 😕
    Der -> Operator wirft eine Ausnahme, wenn der Zeiger tot ist. Die könnte man abfangen. Weiss jemand, wie ich diese Ausnahme identifizieren kann?

    Mit exception geht's nicht, aber mit (...) . 😃
    Gibt's noch was anderes?



  • Hab einen Weg gefunden, nicht schön, aber tut gehen! 😃

    _LIST::iterator iter = m_vList.begin();
    while (iter != m_vList.end()) {
    	try {
    		if(!(*iter)->write()) 
    			break;
    		iter++;
    	} catch (...) {
    		std::cout << "Eine Ausnahme !!!" << std::endl;
    		if (iter==m_vList.begin()) {
    			m_vList.erase(iter);
    			iter = m_vList.begin();
    		} else {
    			iter--;
    			m_vList.erase(iter+1);
    			iter++;
    		}
    	}
    }
    if (iter==m_vList.end()) bStatus = true;
    

    Über Anregungen und Verbesserungen würde ich mich freuen! 🙂



  • don_basto schrieb:

    Der -> Operator wirft eine Ausnahme, wenn der Zeiger tot ist.

    Nope zumindest nicht aus Sicht von Standard-C++. In Standard-C++ führt das einfach zu undefiniertem Verhalten.

    Bin mit der Lösung nicht zufrieden! Muss doch noch einen anderen Weg geben, als es dem Nutzer zu überlassen

    Es gibt viele mögliche Lösungen. Z.B. kannst du deine Observer-Implementation um eine Tracking-Schnittstelle ergänzen:

    class Observer;
    
    class Subject {
    public:
      virtual ~Subject() {}
      virtual void add(Observer* o) = 0;
      virtual void remove(Observer* o) = 0;
    };
    class Observer {
    public:
      virtual ~Observer() {}
      virtual void update() = 0;
    };
    
    class TrackableObserver : public Observer
    {
    public:
       TrackableObserver(Subject* mySubject = 0)
         : mySubject_(mySubject)
       {}
       ~TrackableObserver() {
         mySubject_->remove(this);
       }
       void setSubject(Subject* mySubject) {
         mySubject_ = mySubject;
       }
    private:
      Subject* mySubject_;
    };
    
    class MeineListe : public Subject
    {
    public:
      MeineListe() {}
      void add(Observer* o) {
        if (find(observers_.begin(), observers_.end(), o) == observers_.end())
        {
          observers_.push_back(o);
          if (TrackableObserver* t = dynamic_cast<TrackableObserver*>(o))
            t->setSubject(this);
        }
      }
      void remove(Observer* o) {
        std::vector<Observer*>::iterator it = find(observers_.begin(), observers_.end(), o);
        if (it != observers_.end())
          observers_.erase(it);
      }
      void notify() {
        for (std::vector<Observer*>::iterator it = observers_.begin(); it != observers_.end(); ++it)
          (*it)->update();
      }
    private:
      std::vector<Observer*> observers_;
    };
    
    class Foo : public TrackableObserver {
    public:
      void update() {
        cout << "Foo::update" << endl;
      }
    };
    
    int main() {
      MeineListe l;
      {
        Foo f;
        l.add(&f);
        l.notify();
        // Dtor von f meldet f automatisch ab
      }
      l.notify();
    
    }
    


  • @don_basto
    Der von dir gepostete Code ist nicht portable. Der Zugriff auf ein nicht mehr existierendes Objekt ist illegal. Niemand garantiert dir, dass in diesem Moment eine Exception geworfen wird. Du scheinst unter Windows zu arbeiten. Dort wird in diesem Fall eine SEH-Exception geworfen. Diese Exceptions sind aber Windows-spezifisch und haben nichts mit Standard-C++ Exceptions zu tun.



  • HumeSikkins schrieb:

    @don_basto
    Der von dir gepostete Code ist nicht portable. Der Zugriff auf ein nicht mehr existierendes Objekt ist illegal. Niemand garantiert dir, dass in diesem Moment eine Exception geworfen wird. Du scheinst unter Windows zu arbeiten. Dort wird in diesem Fall eine SEH-Exception geworfen. Diese Exceptions sind aber Windows-spezifisch und haben nichts mit Standard-C++ Exceptions zu tun.

    Nur dass nichtmal unter Windows diese Exception garantiert wird.
    Denn vielleicht ist dort zufällig ein legales Objekt? Ist ja nicht so absurd, dass hier:

    p=new C;
    delete p;
    p2=new C;
    

    p2 die selbe adresse zugewiesen bekommt wie p 😉

    ne, hardware exception sind etwas, dass sollte man vermeiden... es ist schön, dass eine fliegt, aber erwarten sollte man sie nicht.



  • Da Portabilität häufig als alleiniges Argument nicht überzeugt, hier noch eine Ergänzung zu meinem letzten Beitrag:

    don_basto schrieb:

    Hab einen Weg gefunden, nicht schön, aber tut gehen! 😃

    Nö tut er nicht. Er schützt dich nur vor einer Sorte von Fehlern - Zugriff auf Speicher der deinem Prozess nicht gehört. Nun kann es aber passieren, dass du ein Objekt zerstörst (ohne es abzumelden), der Speicher für ein neues Objekt aber wiederverwendet wird. Damit referenziert dein Zeiger in der Liste aufeinmal ein Objekt, dass sich nie angemeldet hat. Sollte das neue Objekte layout-kompatibel zum alten Objekt sein, wird dieser Fehler nicht bemerkt und du kannst ohne weiteres den dritten Weltkrieg auslösen. Wie du an folgendem Beispiel unschwer erkennen kannst:

    #include <windows.h>
    
    inline int handle_seh(DWORD excode)
    {
      if (excode == EXCEPTION_ACCESS_VIOLATION) 
      {
        cout << "Error-Access" << endl;
        return EXCEPTION_EXECUTE_HANDLER;
      }
      return EXCEPTION_CONTINUE_SEARCH;
    }
    
    class MeineListe : public Subject
    {
    public:
      MeineListe() {}
      void add(Observer* o) {
        if (find(observers_.begin(), observers_.end(), o) == observers_.end())
        {
          observers_.push_back(o);
          if (TrackableObserver* t = dynamic_cast<TrackableObserver*>(o))
            t->setSubject(this);
        }
      }
      void remove(Observer* o) {
        std::vector<Observer*>::iterator it = find(observers_.begin(), observers_.end(), o);
        if (it != observers_.end())
          observers_.erase(it);
      }
      void notify() {
        for (std::vector<Observer*>::iterator it = observers_.begin(); it != observers_.end(); ++it)
          __try {
            (*it)->update();  
          }
          __except(handle_seh(::GetExceptionCode())) {}
      }
    private:
      std::vector<Observer*> observers_;
    };
    
    class Flower : public Observer {
    public:
      void update() {
        cout << "Ich bin eine Blume und ich bringe Liebe und Frieden!" << endl;
      }
    };
    
    class NuclearSubmarine : public Observer {
    public:
      void update() {
        cout << "Ich bin ein Atom-U-Boot und ich bringe Tod und Vernichtung!" << endl;
      }
    };
    
    int main() {
      MeineListe flowers;
      MeineListe navy;
    
      // Placement-new verwende ich hier nur zur Demonstration.
      // Effekt: u wird im Speicher den zuvor f bewohnte geboren.
      // Das kann immer passieren! 
      // Der Allokator des VC 6.0 würde dies hier z.B. auch ganz automatisch
      // so machen. Man könnte hier also auch einfach new/delete verwenden und
      // hätte das gleiche katastrophale Ergebnis. 
      void* b = ::operator new(sizeof(Flower));
      Flower* f = new (b) Flower;
    
      flowers.add(f);   // Überall Krieg und Leid auf der Welt,
      flowers.notify(); // es ist mal wieder Zeit für eine Anti-Kriegsdemonstration!
    
      f->~Flower();     // Demo zuende! Die Blume stirbt ohne sich abzumelden!
    
      NuclearSubmarine* u = new (b) NuclearSubmarine;
      navy.add(u);  // Geil! Endlich haben wir auch ein Atom-U-Boot!
    
      flowers.notify();   // Die Atomkraftgegner sind empört, sie demonstrieren...
                          // und, o weh, starten damit den dritten Weltkrieg!
      ::operator delete(b);
    }
    


  • @Shade
    Sorry. Habe während ich meinen Beitrag schrieb nicht aktualisiert und deshalb deine Antwort nicht bemerkt. Naja, doppelt hält besser 😉



  • HumeSikkins schrieb:

    @Shade
    Sorry. Habe während ich meinen Beitrag schrieb nicht aktualisiert und deshalb deine Antwort nicht bemerkt. Naja, doppelt hält besser 😉

    Ach, ich lese deine Beiträge gerne. Die sind meistens so richtig cool, wie zB der hier wieder. Atom-UBoote, Weltfrieden, Zerstörung,... und das alles nur, weil jemand eine 'Ausnahme' machen will 😉



  • Och, ich dachte Hume mag so gerne Beispiele mit Elefanten ;). Versprich uns Hume,
    dass du die beim naechsten mal wieder bringst 👍.

    mfg
    v R 🙂



  • virtuell Realisticer schrieb:

    Och, ich dachte Hume mag so gerne Beispiele mit Elefanten ;). Versprich uns Hume,
    dass du die beim naechsten mal wieder bringst 👍.

    Ein "Elefant im Porzellanladen"-Beispiel (verdammt ich hatte doch gar keinen Elefant reingelassen...) wäre sicher auch nicht schlecht gewesen. Im Zuge der Reitzüberflutung muss man heutzutage aber schon spektakuläreres bieten um überhaubt noch gehört zu werden (ein Elefanten müsste mindestens bekloppt und auf's Handy ladbar sein) 😉

    Aber kommen wir zum Thema zurück...



  • .. jetzt läuft mein Prog nach C++-Standard. 😃
    Danke für das Tracking-Beispiel, hab's jetzt so implementiert und das funzt super. 👍


Anmelden zum Antworten