2017-01-09 4 views
0

Gibt es eine Möglichkeit, in C++ zu bestimmen, ob eine Methode zur Laufzeit rein virtuell ist? In der Tat ist die Frage, ob es einen Weg gibt zu wissen, ob der Destruktor einer abgeleiteten Klasse bereits ausgeführt wurde, aber die Basisklasse noch am Leben ist.Ermitteln, ob eine Methode rein virtuell ist (C++)

Das ist mein Fall (vereinfacht):.

class BaseClass{ 
private: 
    class ThreadUtil *threadUtil; 
public: 
    Mutex mutex; 
    ~BaseClass(){ 
       threadUtil->Terminate(); 
       MutexLocker ml(mutex); // Avoid destruction during use 
    } 

    virtual Size size()=0; 
}; 

class Derived:public BaseClass{ 
public: 
    Size size()override{return Size(100,80);} 
}; 


class ThreadUtil{ 
private: 
    bool terminate; 
    BaseClass *owner; 

public: 
    void Run(){ 
     while(!terminate){ 
      if (!IS_OWNER_SIZE_FN_PURE_THAT_S_THE_QUESTION){ 
       MutexLocker ml(owner->mutex); 
       DoSomething(owner->size()); // Runtime error if in the dtor of BaseClass 
      } 
     } 
    } 
}; 

A „rein virtuelle Funktion namens“ (wenn DoSomething aufgerufen wird, während ~ Baseclass ausgeführt wird

Terminieren des Fadenlaufzeitfehler sehr sporadisch geschieht + Locking in der abgeleiteten Klasse ist sicher, aber ich möchte es in der BaseClass tun (vor allem, wenn es viele abgeleitete Klassen gibt)

Gibt es eine tragbare und sauber (keine Flags herum) Weg dies zu implementieren ?. .. oder was ist falsch mit dem oben genannten d esign?

Edit: --------------------

Wie einige erwähnt haben, die rein virtuelle ist nicht das eigentliche Problem. Es tritt in den Destruktor der Basisklasse ein, während der Thread noch läuft. Die eigentliche Frage sollte vielleicht sein „? ist es eine Möglichkeit, eine Pre-destructor Methode in einer Basisklasse haben

In Is there any automated way to implement post-constructor and pre-destructor virtual method calls? wies von Jeremy Friesner, gibt es eine interessante Idee:

  • Herstellung Der Destruktor der Basis und abgeleitete Klassen, die so geschützt sind, können nicht aufgerufen werden.
  • Den Destruktor von BaseClass virtuell machen.
  • in der Basisklasse Implementierung Löschen(), die zuerst den Thread beendet und ruft dann den destructor (als virtuelle abgeleitete Destruktoren aufgerufen werden)
+1

Warum ist Ihr Basisklassen-Destruktor nicht virtuell? –

+2

Sie möchten keine virtuellen Funktionen von dtor aufrufen, nicht nur reine, normalerweise –

+4

Pure virtual ist ein Red Hering hier. Das eigentliche Problem ist, dass 'Run' versucht, auf das Objekt zuzugreifen, wenn es nicht mehr existiert. Die Lösung besteht darin, das Eigentum richtig zu verwalten, z. Verwenden von 'std :: shared_ptr/weak_ptr' anstelle des rohen Zeigers. –

Antwort

7

Sie bellen hier den falschen Baum - in einer korrekten C++ Programm ist es unmöglich, eine reine virtuelle Funktion aufzurufen (weil der Aufrufversuch vom Compiler als Fehler gemeldet wird), so dass zur Laufzeit nicht festgestellt werden muss, ob eine Funktion rein virtuell ist oder nicht.

Der Grund, warum Sie den Fehler "pure virtual function called" bekommen, liegt manchmal daran, dass Ihr Programm fehlerhaft ist - insbesondere leidet es unter einer Race Condition, bei der Ihre Run() -Methode Methoden auf einem Objekt aufruft im Prozess der Zerstörung.

Was Sie hier tun müssen, ist sicherzustellen, dass der Thread beendet wurde (indem Sie den Thread zum Beenden auffordern und dann pthread_join() aufrufen oder eine andere API, die so lange blockiert, bis der Thread 100 hat % weggegangen) vor alle Objekte zu zerstören, die der Thread zugreifen könnten während der Ausführung. Nur Ihre Bereinigung nach beginnen die der Faden ist tot, und auf diese Weise werden Sie die race-Bedingung zu vermeiden und damit die Fehler/Absturz.

Beachten Sie, dass es nicht funktioniert, den Aufruf pthread_join() in die Destructor-Methode Ihrer BaseClass zu platzieren, da zu dem Zeitpunkt, zu dem Ihre BaseClass-Destruktorfunktion ausgeführt wird, die Unterklassen-Ebenen des Objekts bereits vorhanden sind wurde zerstört. Sie müssen den Thread vor löschen das Objekt löschen, von dem BaseClass die Oberklasse ist.(Zugegeben, es ist ein wenig umständlich diese Sequenz in C++ zu automatisieren, da AFAICT Sie die Anrufer müssen sicherstellen, ruft die Vor-Löschen-Thread-Shutdown-Funktion manuell, insbesondere gibt es no easy/automatic/transparent way to automate the generation of the pre-destructor thread-shutdown code)

+1

Ja, das rein virtuelle ist nicht das eigentliche Problem. Es tritt in den Destruktor der Basisklasse ein, während der Thread noch läuft. Die tatsächliche Frage sollte vielleicht lauten: "Gibt es eine Möglichkeit, eine Vordestrukturierungsmethode in einer Basisklasse zu verwenden?" In dem Link, gibt es eine interessante Idee: - Making the destructor die Basis und abgeleiteten Klassen Privat kann so löscht nicht aufgerufen wird - macht den destructor virtuell. - Implementieren in der Basisklasse Delete(), die zuerst den Thread beendet und dann den Destruktor aufruft (so virtuell, dass abgeleitete Destruktoren aufgerufen werden) – Joan

0

Gibt es eine portable und sauber (keine Flaggen herum) Weg, dies zu implementieren? ... oder was ist los mit dem oben genannten Design?

Tragbare und saubere Möglichkeit ist es zu verhindern, dass das Objekt zerstört wird, bevor der Thread beendet wird. Dies kann erreicht werden, indem die Klasse TheradUtil Eigentümerschaft an BaseClass durch einen intelligenten Zeiger des richtigen Typs besitzt.

Verwandte Themen