Avertissement du compilateur GNU: «la classe a des fonctions virtuelles mais un destructeur non virtuel»

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

  •  02-07-2019
  •  | 
  •  

Question

J'ai défini une interface en C ++, c'est-à-dire une classe contenant uniquement des fonctions virtuelles pures.

Je veux interdire explicitement aux utilisateurs de l'interface de supprimer l'objet via un pointeur sur l'interface. J'ai donc déclaré un destructeur protégé et non virtuel pour l'interface, par exemple:

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

protected:
    ~ITest(){}
};

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

Le compilateur GNU me donne un avertissement disant:

  

la classe 'ITest' a des fonctions virtuelles mais un destructeur non virtuel

Une fois le destructeur protégé, quelle est la différence de l’avoir virtuel ou non virtuel?

Pensez-vous que cet avertissement peut être ignoré ou réduit au silence en toute sécurité?

Était-ce utile?

La solution

C'est plus ou moins un bug dans le compilateur. Notez que dans les versions plus récentes du compilateur, cet avertissement n'est pas émis (du moins dans la version 4.3, il ne l'est pas). Faire en sorte que le destructeur soit protégé et non virtuel est tout à fait légitime dans votre cas.

Voir ici pour un excellent article de Herb Sutter sur le sujet. De l'article:

Directive n ° 4: un destructeur de classe de base doit être public et virtuel, ou protégé et non virtuel.

Autres conseils

Certains commentaires sur cette réponse se rapportent à une réponse précédente que j'ai donnée, qui était fausse.

Un destructeur protégé signifie qu'il ne peut être appelé qu'à partir d'une classe de base, et non par suppression. Cela signifie qu’un ITest * ne peut pas être supprimé directement, seule une classe dérivée le peut. La classe dérivée peut très bien vouloir un destructeur virtuel. Il n'y a rien de mal avec votre code.

Cependant, étant donné que vous ne pouvez pas désactiver localement un avertissement dans GCC et que vous avez déjà une table vtable, vous pouvez quand même envisager de rendre le destructeur virtuel. Cela vous coûtera 4 octets pour le programme (pas par instance de classe), maximum. Puisque vous avez peut-être donné à votre classe dérivée un dtor virtuel, vous constaterez que cela ne vous coûte rien.

Si vous insistez pour cela, continuez et transmettez -Wno-non-virtual-dtor à GCC. Cet avertissement ne semble pas être activé par défaut. Vous devez donc l'avoir activé avec -Wall ou -Weffc ++ . Cependant, je pense que c'est un avertissement utile, car dans la plupart des situations, il s'agirait d'un bug.

C'est une classe d'interface, il est donc raisonnable de ne pas supprimer les objets implémentant cette interface via cette interface. Un cas courant de cela est une interface pour les objets créés par une fabrique qui devrait être renvoyée à la fabrique. (Avoir des objets contenant un pointeur sur leur usine peut être assez coûteux).

Je suis d'accord avec l'observation selon laquelle GCC se plaint. Au lieu de cela, il devrait simplement vous avertir lorsque vous supprimez un ITest *. C'est là que réside le vrai danger.

Mon opinion personnelle est que vous feriez la bonne chose et que le compilateur est en panne. Je désactiverais l'avertissement (localement dans le fichier qui définit l'interface) si possible,

Je trouve que j'utilise beaucoup ce motif (petit "p"). En fait, je trouve qu'il est plus courant que mes interfaces aient des détecteurs protégés que d'avoir des interfaces publiques. Cependant, je ne pense pas que ce soit vraiment un idiome courant (on n'en parle pas beaucoup) et je suppose que lorsque l'avertissement a été ajouté à GCC, il était approprié d'essayer de faire appliquer l'ancien «dtor» doit être virtuel si vous avoir la règle des fonctions virtuelles. Personnellement, j’ai mis à jour cette règle en 'dtor doit être virtuel si vous avez des fonctions virtuelles et souhaitez que les utilisateurs puissent supprimer des instances de l’interface via l’interface, sinon le dtor doit être protégé et non virtuel il y a longtemps;)

Si le destructeur est virtuel, il s'assure que le destructeur de la classe de base est également appelé avant d'effectuer le nettoyage, sinon certaines fuites peuvent résulter de ce code. Vous devez donc vous assurer que le programme ne contient pas de tels avertissements (pratiquement aucun avertissement).

Si vous aviez un code dans l'une des méthodes de ITest qui essayait de supprimer lui-même (une mauvaise idée, mais légal), le destructeur de la classe dérivée ne serait pas appelé. Vous devez quand même rendre votre destructeur virtuel, même si vous n'avez jamais l'intention de supprimer une instance dérivée via un pointeur de classe de base.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top