web-dev-qa-db-fra.com

Quelle est la signification des -wweak-vtables de clang?

Je ne comprends pas fondamentalement _ -Wweak-vtables. Voici ce que j'ai observé jusqu'à présent:

Premier cas: (déclenche l'avertissement)

class A {
    public:
    virtual ~A(){}        
};

class B : public A {
    public:
    virtual ~B(){}
};

int main(){}

Cas deux: (Ne déclenche pas d'avertissement)

class A {
    public:
    virtual ~A(){}        
};   

int main(){}

Troisième cas: (Ne déclenche pas d'avertissement)

class A {
    public:
    virtual ~A();

};

A::~A(){}

class B : public A {
    public:
    virtual ~B(){}
};

int main(){}

Cas quatre: (Avertissement de déclencheurs)

class A {
    public:
    virtual ~A(){}
    virtual void fun(){}        
};    

class B : public A {
    public:
    virtual ~B(){}
};

int main(){}

Cas cinq: (Ne déclenche pas d'avertissement)

class A {
    public:
    virtual ~A(){}
    virtual void fun();      
};    

class B : public A {
    public:
    virtual ~B(){}
};

int main(){}

Cas six: (Ne déclenche pas d'avertissement)

class A {
    public:
    virtual ~A(){}
    virtual void fun(){}
};    

class B : public A {};

int main(){}

Cas sept: (Ne déclenche pas d'avertissement)

class A {
    public:
    virtual ~A(){}
    virtual void fun(){}
};    

class B : public A {
    public:
    virtual void fun(){}
};

int main(){}

L'avertissement exact est

warning: 'A' has no out-of-line virtual method definitions; its vtable 
will be emitted in every translation unit [-Wweak-vtables]

Donc apparemment, si je ne déclare pas une fonction virtuelle non en ligne dans une classe, cela pose une sorte de problème si et seulement si j'en dérive et que la classe dérivée a un destructeur virtuel.

Questions:

  1. Pourquoi c'est un problème?
  2. Pourquoi cela se résout-il en déclarant une fonction virtuelle? (L'avertissement parle de définitions)
  3. Pourquoi l'avertissement ne se produit-il pas lorsque je ne dérive pas de la classe?
  4. Pourquoi l'avertissement ne se produit-il pas lorsque la classe dérivée n'a pas de destructeur virtuel?
69
Baum mit Augen

Si toutes les méthodes virtual d'une classe sont en ligne, le compilateur n'a aucun moyen de sélectionner une unité de traduction dans laquelle placer une seule copie partagée de la vtable - à la place, une copie de la vtable doit être placée dans chaque fichier objet qui en a besoin. Sur de nombreuses plates-formes, l'éditeur de liens est en mesure d'unifier ces multiples copies, soit en supprimant les définitions en double, soit en mappant toutes les références à une seule copie, ce n'est donc qu'un avertissement.

L'implémentation d'une fonction virtual hors ligne permet au compilateur de sélectionner l'unité de traduction qui implémente cette méthode hors ligne comme "home" pour les détails d'implémentation de la classe, et place la copie partagée unique de la vtable dans la même unité de traduction. Si plusieurs méthodes sont hors ligne, un choix arbitraire de méthode peut être effectué par le compilateur tant que ce choix n'est déterminé que par la déclaration de la classe; par exemple, GCC choisit la première méthode non en ligne dans l'ordre de déclaration.

Si vous ne remplacez aucune méthode d'une classe, le mot clé virtual n'a aucun effet observable, il n'est donc pas nécessaire que le compilateur émette une vtable pour la classe. Si vous ne dérivez pas de A, ou si vous ne déclarez pas le destructeur d'une classe dérivée virtual, il n'y a pas de méthodes substituées dans A et donc A vtable est omis. Si vous déclarez une méthode virtual hors ligne supplémentaire pour supprimer l'avertissement et faites quelque chose qui remplace une méthode dans A, l'implémentation de la méthode non en ligne virtual (et la copie qui l'accompagne de la table virtuelle) doit être fournie dans une unité de traduction liée, sinon la liaison échouera car la table virtuelle est manquante.

94
Jeffrey Hantin