Sondage : Le mot clé inline est-il encore d'actualité ?
Donnez votre avis

Le , par Aurelien.Regat-Barrel, Expert éminent
Bonjour,

En ce moment je passe des entretiens et donc des tests techniques C++, et j'ai eu droit à une question sur "virtual inline". J'en ai profité pour glisser mon avis personnel au sujet de inline qui est en gros : ce n'est plus utile de nos jours. Maintenant, je me demande dans quelle mesure mon affirmation est valide.

Je n'ai jamais été un grand fan de inline (explicite ou implicite), parce que de mon point de vue c'est une entorse aux bonnes pratiques (pas d'implémentation dans un header) du fait que, ben, on en avait besoin. Mais aujourd'hui - sans m'être sérieusement penché sur la question je l'avoue - j'estime que les compilateurs sont suffisamment évolués pour se débrouiller tout seuls, surtout avec l'apparition de l'optimisation guidée par profil (encore que j'ai eu des déceptions à ce sujet). Bref, je considère qu'inline relève de l'optimisation prématurée, pour ne pas dire de la pollution de code, et que c'est à oublier au même titre que register.

Vos avis / retours d'expérience ?


Vous avez aimé cette actualité ? Alors partagez-la avec vos amis en cliquant sur les boutons ci-dessous :


 Poster une réponse

Avatar de deubelte deubelte - Débutant http://www.developpez.com
le 18/03/2010 à 23:31
En ce moment je passe des entretiens et donc des tests techniques C++, et j'ai eu droit à une question sur "virtual inline".

Moi, en ce moment, j'étudie qqch qui parle exactement de virtual inline, mais pour le cas particulier des destructeurs. Si j'ai bien compris, inline insert le code dans la fonction main, ce qui fait que la fonction n'a plus vraiment d'adresse. Le problème est que virtual crée automatiquement une adresse mémoire pour la vtbl afin que le pointeur vptr pointe entre autre sur cette adresse.
ce qui fait que l'apport de inline est annulé par virtual

Je reproduis le commentaire du livre:

Because your destructor is virtual, its address must be entered into the class's vtbl. But inline
functions aren't supposed to exist as freestanding functions (that's what inline means, right?), so special measures
must be taken to get addresses for them. The bottom line is this: if you declare a
virtual destructor inline, you're likely to avoid function call overhead when it's invoked, but your compiler will
still have to generate an out-of-line copy of the function somewhere, too.

Avatar de koala01 koala01 - Expert éminent sénior http://www.developpez.com
le 18/03/2010 à 23:53
Citation Envoyé par deubelte  Voir le message
Moi, en ce moment, j'étudie qqch qui parle exactement de virtual inline, mais pour le cas particulier des destructeurs. Si j'ai bien compris, inline insert le code dans la fonction main, ce qui fait que la fonction n'a plus vraiment d'adresse. Le problème est que virtual crée automatiquement une adresse mémoire pour la vtbl afin que le pointeur vptr pointe entre autre sur cette adresse.
ce qui fait que l'apport de inline est annulé par virtual

A vrai dire, l'inlining d'un destructeur virtuel n'a, purement et simplement, aucun sens (pas plus d'ailleurs que l'inlining de n'importe quelle autre fonction virtuelle ).

En effet, lorsque tu déclare (dans la classe parent) une fonction virtuelle, c'est comme si tu disais au compilateur:
Le comportement de cette fonction peut changer en fonction du type réel (dynamique) de l'objet au départ duquel la fonction est invoquée

Or, il faudra déterminer dynamiquement (à l'exécution) le type réel de l'objet uniquement si... on le fait passer pour un objet du type de la classe parent (ancêtre).

Cela implique fatalement que... le type réel de l'objet est... inconnu au moment de la compilation.

Dés lors, comment voudrais tu que le compilateur sache par quoi il devra remplacer l'appel, alors qu'il ne sait même pas exactement au départ de quel type d'objet cet appel est effectué

Bien sur, si tu as, simplement un
Code : Sélectionner tout
Base mabase;
ou un
Code : Sélectionner tout
Derivee maderivee;
(étant entendu que Derivee hérite de Base ) il n'y aura aucun problème pour déterminer par quoi remplacer l'appel d'une fonction virtuelle, mais ce n'est, typiquement, pas dans ce cas que la virtualité intervient.

Par contre, la virtualité des fonction interviendra forcément si tu as un
Code : Sélectionner tout
Base * ptr=new Base;
ou un
Code : Sélectionner tout
Base * ptr=new Derivee;
et là, il sera tout à fait hors de question pour le compilateur d'inliner l'appel, simplement, parce qu'il doit s'assurer de passage par... la table de fonctions virtuelles afin d'être sur que version de la fonction invoquée correspond bien au type dynamique au départ duquel elle est invoquée.
Avatar de metagoto metagoto - Membre éclairé http://www.developpez.com
le 19/03/2010 à 0:33
Citation Envoyé par koala01  Voir le message
A vrai dire, l'inlining d'un destructeur virtuel n'a, purement et simplement, aucun sens (pas plus d'ailleurs que l'inlining de n'importe quelle autre fonction virtuelle ).

Mais si le destructeur, virtuel ou non, est défini dans la classe, la fonction est "inline". Si en plus le destructeur est vide (ce qui arrive), là je pense qu'un compilo pourrait vraiment inliner.

Aussi, rien n'empêche de manipuler un objet par son type statique et donc potentiellement de caller son destructeur, au demeurant inline et virtuel (dans la déclaration). Ca ne me parait pas incompatible, et on tombe sur la citation précédente de deubelte.
Avatar de koala01 koala01 - Expert éminent sénior http://www.developpez.com
le 19/03/2010 à 0:40
Citation Envoyé par metagoto  Voir le message
Mais si le destructeur, virtuel ou non, est défini dans la classe, la fonction est "inline". Si en plus le destructeur est vide (ce qui arrive), là je pense qu'un compilo pourrait vraiment inliner.

A ceci près que la vtbl ne sera pas créée (ou en tout cas, le destructeur ne sera pas référencé dans la vtbl)...

Cela compilera (comprend: le compilateur ne bronchera pas), mais l'éditeur de liens t'enverra cueillir des pâquerettes lorsqu'il s'agira de tout remettre en ordre.
Aussi, rien n'empêche de manipuler un objet par son type statique et donc potentiellement de caller son destructeur, au demeurant inline et virtuel (dans la déclaration). Ca ne me parait pas incompatible, et on tombe sur la citation précédente de deubelte.

C'est sympa de me répéter (car j'ai aussi exprimé ce point de vue ), mais, encore une fois, tu risques fortement de te faire jeter par l'éditeur de liens
Avatar de deubelte deubelte - Débutant http://www.developpez.com
le 19/03/2010 à 8:53
A ceci près que la vtbl ne sera pas créée (ou en tout cas, le destructeur ne sera pas référencé dans la vtbl)...

Et pour quelles raisons? Est-ce parce que le destructeur est déclaré dans la classe?

Dans VC2010, est-il possible d'acceder à la vtbl?
Avatar de 3DArchi 3DArchi - Rédacteur http://www.developpez.com
le 19/03/2010 à 10:55
Citation Envoyé par deubelte  Voir le message
Dans VC2010, est-il possible d'acceder à la vtbl?

Directement, non. Cependant, tu peux voir la façon dont c'est utilisé en regardant le code ASM. Regardes ici : Les fonctions virtuelles en C++ : Comment ça marche ?
Avatar de Lavock Lavock - Membre confirmé http://www.developpez.com
le 23/03/2010 à 10:07
Héhé, c'est le fameux problème du :

Code : Sélectionner tout
1
2
3
struct A { 
   virtual ~A() {}; 
}
Je me suis toujours demandais, mais il faudrait tester, si l'inlining dans se cas n'inlinerai pas plutôt les processus de résolution de virtualité. [edit] <= Stupide ! Mais est-il possible d'inliné la fonction dans la résolution de polymorphisme elle même ?

[edit] Au passage, c'est loin d'être "interdit".

Par défaut, je pensais qu'un virtual inline procédé comme ceci :
En cas d'appel polymorphique, on résout celui-ci.
Sinon, en cas d'appel direct, on applique le cas classique.
Avatar de white_tentacle white_tentacle - Membre émérite http://www.developpez.com
le 23/03/2010 à 13:42
Citation Envoyé par koala01  Voir le message
A ceci près que la vtbl ne sera pas créée (ou en tout cas, le destructeur ne sera pas référencé dans la vtbl)...

Cela compilera (comprend: le compilateur ne bronchera pas), mais l'éditeur de liens t'enverra cueillir des pâquerettes lorsqu'il s'agira de tout remettre en ordre.

C'est sympa de me répéter (car j'ai aussi exprimé ce point de vue ), mais, encore une fois, tu risques fortement de te faire jeter par l'éditeur de liens

Je ne pense pas.

Le compilateur sait à la compilation si un appel est virtuel ou pas. Donc, il sait s'il peut inliner le code du destructeur, ou s'il doit passer par le destructeur virtuel.

C'est le sens de :

The bottom line is this: if you declare a virtual destructor inline, you're likely to avoid function call overhead when it's invoked, but your compiler will still have to generate an out-of-line copy of the function somewhere, too.

Qui grosso-modo dit que si tu déclares ton destructeur virtuel inline, le compilateur pourra l'inliner dans certains cas, mais devra de toute manière générer une version non-inline dudit destructeur.
Avatar de gb_68 gb_68 - Membre averti http://www.developpez.com
le 23/03/2010 à 22:17
+1
Citation Envoyé par deubelte  Voir le message
Le problème est que virtual crée automatiquement une adresse mémoire pour la vtbl afin que le pointeur vptr pointe entre autre sur cette adresse.
ce qui fait que l'apport de inline est annulé par virtual

Je crois que la génération ou non de code pour une fonction n'est pas lié à l'inline de celle-ci (mais peut en être une conséquence possible). Il existe plusieurs cas où une fonction, même inline, DOIT avoir un code généré ainsi qu'une adresse ; bien sûr si elle est membre virtuelle, mais aussi si l'on prend son adresse (par exemple pour la stocker), si elle est récursive, si elle est exportée, si le compilateur décide de ne pas l'étendre à certains endroits. En revanche, cela n'affecte pas la possibilité de voir cette fonction étendue à d'autres endroits (et de gagner un appel de fonction). Donc l'apport du inline n'est pas annulé.
Inversement, une fonction non inline peut être supprimée, à l'édition des liens, si elle n'est jamais appelée (ce qui a peu d'intérêt en soi ).
Citation Envoyé par koala01  Voir le message
A vrai dire, l'inlining d'un destructeur virtuel n'a, purement et simplement, aucun sens (pas plus d'ailleurs que l'inlining de n'importe quelle autre fonction virtuelle ).

Il est pourtant possible dans une classe fille d'appeler une fonction membre héritée virtuelle de manière "non polymorphique". Cela est même toujours le cas pour un destructeur, qui appel automatiquement ses ancêtres.
[HS] Après, il faut tout de même être prudent avec les destructeurs inline (un destructeur vide peut quand même être volumineux et un destructeur inline est sujet aux mêmes dangers qu'un destructeur auto généré -> cf. destruction d'un type incomplet).[HS]
Avatar de koala01 koala01 - Expert éminent sénior http://www.developpez.com
le 23/03/2010 à 22:41
Citation Envoyé par gb_68  Voir le message
Il est pourtant possible dans une classe fille d'appeler une fonction membre héritée virtuelle de manière "non polymorphique".

Le fait est que la gestion de l'inlining se fait... à la compilation, alors que la gestion de la virtualité ne se fait ... qu'au runtime...

Comme on l'a vu, en simplifiant à l'extrême, l'inlining va dire au compilateur de remplacer l'appel de la fonction par le code de celle-ci (même s'il y a certaines restrictions )

Par contre, l'appel d'une fonction virtuelle va dire au compilateur de rajouter du code allant chercher dans la vtbl l'adresse réelle de la fonction qui est appelée, et ce passage par la vtbl sera obligatoire dés le moment où tu travailles avec une référence ou un pointeur, pour la simple et bonne raison qu'il sera incapable de déterminer si la référence (ou le pointeur) ne fait pas passer une instance d'une classe dérivée pour la classe de base.

Le compilateur ne pourra donc quasiment jamais inliner l'appel d'une fonction virtuelle.[EDIT]Du moins, jamais si l'appel est suspecté d'être polymoprhique[/EDIT]

De plus, on remarque que, même si c'est du à un bug, certains compilateurs ne créent effectivement pas de vtbl s'il n'y a aucune fonction virtuelle non inline (c'était, me semble-t-il, le cas pour a version antérieure de MinGW), ce qui se traduit immanquablement par une erreur à l'édition de liens
Avatar de gb_68 gb_68 - Membre averti http://www.developpez.com
le 24/03/2010 à 21:04
Citation Envoyé par koala01  Voir le message
Le fait est que la gestion de l'inlining se fait... à la compilation, alors que la gestion de la virtualité ne se fait ... qu'au runtime...

Oui, mais à la compilation la nature de l'appel est définie (virtuel ou non virtuel) et le code est généré en fonction (non virtuel -> possibilité d'inline ?, virtuel -> accès à la vtbl). Même pour un fonction déclarée virtuelle, il existe des cas d'appel où la virtualité n'entre pas en compte.
Citation Envoyé par koala01  Voir le message
Le compilateur ne pourra donc quasiment jamais inliner l'appel d'une fonction virtuelle.[EDIT]Du moins, jamais si l'appel est suspecté d'être polymoprhique[/EDIT]

L'exemple que je donnais sur la classe fille appelant une fonction membre héritée virtuelle de manière "non polymorphique" n'est pas si rare (cf. cas des destructeurs).
Code : Sélectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class Base 
{ 
public: 
   virtual ~Base() 
   { /*...*/ } 
}; 
 
class Deriv  : public Base 
{ 
public: 
   virtual ~Deriv(); 
   /*...*/ 
}; 
 
void SomeFunction() 
{ 
   Base * ptr =new Deriv();  
   /*...*/ 
   delete ptr; // <- ici, le polymorphisme entre en jeu 
} 
 
Deriv::~Deriv() 
{ 
   /*...*/ 
 
   // appel automatique de Base::~Base() <- ici pas de polymorphisme, 
   // l'inline est possible    
}
Un destructeur virtuel inline semble donc plus que cohérent si l'on souhaite gagner un appel de fonction dans les destructeurs des classes dérivées.
Offres d'emploi IT
Développeur c++ h/f
maureen.halgrin@sanpalrecruitment.com - Ile de France - Paris (75009)
Ingénieur développement logiciel H/F
Sagemcom - Ile de France - Rueil-Malmaison (92500)
Ingénieur Développement Banc de test Labview
FIME - Basse Normandie - Caen (14000)

Voir plus d'offres Voir la carte des offres IT
Contacter le responsable de la rubrique C++