GNU Compiler-Warnung „Klasse hat virtuelle Funktionen aber nicht-virtuellen Destruktor“

StackOverflow https://stackoverflow.com/questions/127426

  •  02-07-2019
  •  | 
  •  

Frage

Ich habe eine Schnittstelle in C ++ definiert, das heißt eine Klasse nur rein virtuelle Funktionen enthält.

Ich möchte ausdrücklich Nutzer der Schnittstelle verbieten das Objekt über einen Zeiger auf die Schnittstelle zu löschen, so erklärte ich einen geschützten und nicht-virtuellen Destruktor für die Schnittstelle, so etwas wie:

class ITest{
public:
    virtual void doSomething() = 0;

protected:
    ~ITest(){}
};

void someFunction(ITest * test){
    test->doSomething(); // ok
    // deleting object is not allowed
    // delete test; 
}

Die GNU Compiler gibt mir eine Warnung sagen:

  

Klasse 'ITest' hat virtuelle Funktionen aber nicht-virtuellen Destruktor

Sobald der destructor geschützt ist, was ist der Unterschied in mit ihm virtuell oder nicht virtuell?

Denken Sie, diese Warnung kann ignoriert oder zum Schweigen gebracht werden?

War es hilfreich?

Lösung

Es ist mehr oder weniger ein Bug im Compiler. Beachten Sie, dass in neueren Versionen des Compilers diese Warnung nicht geworfen bekommt (zumindest in 4.3 es nicht). Nachdem wird der destructor geschützt und nicht virtuell ist völlig legitim, in Ihrem Fall.

Siehe hier für einen ausgezeichneten Artikel von Herb Sutter zu dem Thema. Aus dem Artikel:

Richtlinie Nr. 4: Eine Basisklasse Destruktor sollte entweder öffentliche und virtuelle oder geschützte und nicht-virtuelle sein

Andere Tipps

Einige der Kommentare zu dieser Antwort beziehen sich auf eine frühere Antwort, die ich gab, was falsch war.

Ein geschützter destructor bedeutet, dass es nur von einer Basisklasse aufgerufen wird, nicht durch löschen. Das bedeutet, dass ein ITest * kann nicht direkt gelöscht werden, nur eine abgeleitete Klasse kann. Die abgeleitete Klasse möchten auch einen virtuellen Destruktor. Es ist nichts falsch mit Ihrem Code überhaupt.

Da Sie jedoch nicht vor Ort kann eine Warnung in GCC deaktivieren, und Sie bereits eine VTable haben, könnten Sie betrachten nur die destructor ohnehin virtuellen machen. Es kostet Sie 4 Bytes für das Programm (nicht pro Klasseninstanz), maximal. Da Sie Ihre abgeleitete Klasse eine virtuelle dtor gegeben haben könnte, können Sie feststellen, dass es kostet Sie nichts.

Wenn Sie tun dies darauf bestehen, gehen Sie vor und geben -Wno-non-virtual-dtor zu GCC. Diese Warnung scheint nicht standardmäßig aktiviert werden, so müssen Sie es mit -Wall oder -Weffc++ aktiviert haben. Aber ich denke, es eine nützliche Warnung ist, weil in den meisten Fällen das ein Fehler sein würde.

Es ist eine Interface-Klasse, so ist es sinnvoll, sollten Sie keine Objekte löschen Sie diese Schnittstelle über diese Schnittstelle zu implementieren. Ein häufiger Fall davon ist eine Schnittstelle für Objekte, die von einer Fabrik erstellt, die an das Werk zurückgeschickt werden sollen. (Mit Objekten enthalten einen Zeiger auf ihre Fabrik könnte ziemlich teuer sein).

würde ich mit der Beobachtung überein, dass GCC jammert. Stattdessen sollte es einfach warnen, wenn Sie eine ITest löschen *. Das ist, wo die wirkliche Gefahr liegt.

Meine persönliche Meinung ist, dass Sie die richtige Sache hatten zu tun und der Compiler ist gebrochen. Ich würde die Warnung (lokal in der Datei, die die Schnittstelle definiert) deaktivieren, wenn möglich,

Ich finde, dass ich dieses Muster (small ‚p‘) verwenden ziemlich viel. In der Tat finde ich, dass es häufiger ist für meine Schnittstellen dtors geschützt zu haben, als es für sie ist öffentlich diejenigen zu haben. Allerdings glaube ich nicht, es ist eigentlich, dass gemeinsam ein Idiom (es ist nicht etwa so viel gesprochen bekommt) und ich denke, zurück, wenn die Warnung wurde hinzugefügt, um es angemessen war GCC der ältere ‚dtor muss virtuell sein, wenn Sie zu versuchen, und zu erzwingen haben virtuelle Regel Funktionen. Persönlich aktualisierte ich diese Regel zu ‚dtor virtuell sein muß, wenn Sie virtuelle Funktionen und wünschten Benutzer müssen in der Lage Instanzen der Schnittstelle durch die Schnittstelle zu löschen sonst der dtor geschützt werden sollte und nicht virtuelle‘ vor Ewigkeiten;)

Wenn der Destruktor virtuell ist es stellt sicher, dass die Basisklasse Destruktor auch Vordergrund tat die Bereinigung genannt wird, sonst können einige Lecks aus diesem Code führen. So sollten Sie sicherstellen, dass das Programm keine solche Warnungen hat (prefferably keine Warnungen überhaupt).

Wenn Sie Code in einem der ITest Methoden hatte, die versucht, sich selbst (eine schlechte Idee, aber legal) delete, der Destruktor der abgeleiteten Klasse nicht aufgerufen werden. Sie sollten sich trotzdem Ihre destructor virtuellen machen, auch wenn Sie nie eine abgeleitete Instanz über eine Basisklasse Zeiger löschen wollen.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top