OVH Cloud OVH Cloud

inline, utilisation

21 réponses
Avatar
none
Quelles sont les motivations qui peuvent me pousser à utiliser des
méthodes inline ?
Par exemple, j'ai une classe avec des membres privés dont je déclare des
accesseurs (getFoo, setFoo)

public:
int getFoo() const;
void setFoo(int value);
private:
int m_foot;

Est-il judicieux de déclarer getFoo et setFoo en inline d'emblée, en
sachant que ce sont des fonctions au contenu trivial et petit (getFoo se
contente de renvoyer m_foot par exemple) ?

Merci pour vos conseils avisés

10 réponses

1 2 3
Avatar
Sylvain
none none wrote on 17/03/2006 00:02:
Quelles sont les motivations qui peuvent me pousser à utiliser des
méthodes inline ?


à "utiliser", que des motivations personnelles.

à "déclarer" (soit par "inline", soit en inlinant explicitement le code
(adjoindre le corps d'une méthode à sa définition dans une déclaration
de classe)), principalement des motivations de performances (ie éviter
les appels plus couteux que le traitement lui-même).

mais dans les 2 cas, les options du compilo vous permettent généralement
a) d'inliner ce qui n'est pas déclarer comme tel (forcer une optim.)
b) de désinliner une déclaration explicite (parfois utile en débug).

Sylvain.

Avatar
Fabien LE LEZ
On Fri, 17 Mar 2006 00:02:27 +0100, none <""(none)"@(none)">:

Est-il judicieux de déclarer getFoo et setFoo en inline d'emblée, en
sachant que ce sont des fonctions au contenu trivial et petit (getFoo se
contente de renvoyer m_foot par exemple) ?


J'ai tendance à écrire

public:
int getFoo() const { return m_foot; }

En effet, ça ne surcharge pas trop la définition de la classe, tout en
donnant d'emblée à la fois la définition et la documentation.

À part ça, je me sers des fonctions inline principalement comme un
hack pour m'éviter de créer un .cpp (et de le rajouter dans le link)
pour des classes très simples.

Quant aux questions de performances, ben... autant laisser le compilo
s'en charger. Si jamais le programme fini est trop lent, on applique
la procédure habituelle : profiler, analyse des goulots
d'étranglement, optimisation.

Avatar
Arnaud Meurgues
Sylvain wrote:

mais dans les 2 cas, les options du compilo vous permettent généralement
a) d'inliner ce qui n'est pas déclarer comme tel (forcer une optim.)
b) de désinliner une déclaration explicite (parfois utile en débug).


De toute manière, le compilateur n'est pas tenu de prendre en compte une
indication inline. La norme précise que ce n'est qu'une indication pour
le compilateur.
Donc, même sans option, rien ne garantit (sauf documentation contraire
du compilateur) que ce qui est indiqué inline le sera et que ce qui ne
l'est pas ne le sera pas.

--
Arnaud

Avatar
kanze
none (none) wrote:

Quelles sont les motivations qui peuvent me pousser à utiliser
des méthodes inline ?


Le profiler a dit que ça ne va pas autrement.

Par exemple, j'ai une classe avec des membres privés dont je
déclare des accesseurs (getFoo, setFoo)

public:
int getFoo() const;
void setFoo(int value);
private:
int m_foot;

Est-il judicieux de déclarer getFoo et setFoo en inline
d'emblée, en sachant que ce sont des fonctions au contenu
trivial et petit (getFoo se contente de renvoyer m_foot par
exemple) ?


Pas vraiment. Le but d'utiliser une fonction, plutôt que de
déclarer les données publiques, c'est justement de pouvoir
changer cette implémentation (par exemple en ajoutant des
vérifications des préconditions, etc.). Or, si la fonction est
inline, cette modification provoque la récompilation de tous les
utilisateurs de ta classe.

Ceci dit, ce n'est pas une règle absolue. Je me sers moi-même
des inline (en dehors de quand le profiler me le dit) dans un
certain nombre de cas :

-- Dans les classes locales, définies dans le .cc, il n'y a pas
de véritable raison de s'en priver.

-- De même dans les templates, actuellement. D'autant plus que
par la passée (et peut-être encore) certains compilateurs
avaient des problèmes avec des classes imbriquées dans une
classe templatée, et que ces problèmes ne se manifestaient
pas si les fonctions de la classe imbriquée était définies
dans la classe même.

-- Dans certains rares cas, les définitions inline permet de se
passer d'un fichier .cc complètement. Surtout dans le cas
des interfaces, je le trouve plus convenable de définir le
destructeur (qui est vide, mais qu'il faut déclarer
pourqu'il soit virtuel) inline que de créer un fichier
source, d'où je génère un objet, qu'il faut mettre dans une
bibliothèque et linké, seulement pour définir une seule
fonction vide.

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Avatar
kanze
Arnaud Meurgues wrote:
Sylvain wrote:

mais dans les 2 cas, les options du compilo vous permettent
généralement
a) d'inliner ce qui n'est pas déclarer comme tel (forcer une optim.)
b) de désinliner une déclaration explicite (parfois utile en débu g).


De toute manière, le compilateur n'est pas tenu de prendre en
compte une indication inline.


Il ne lui n'est pas interdit non plus de générer en ligne une
fonction qui n'est pas déclarée inline. G++, et sans doute bien
d'autres, le font.

La norme précise que ce n'est qu'une indication pour le
compilateur.


Formellement, la différence entre inline et non, c'est qu'une
fonction déclarée inline doit être définie dans toute unité de
traduction qui l'utilise, tandis qu'il est interdit de définir
une fonction non-inline dans plus d'une unité de traduction.

Mais l'intention est claire -- quand on dit « inline », on dit
au compilateur qu'à notre avis, il serait avantageux que cette
fonction soit générée en ligne. Si le compilateur sait
réelement faire le choix mieux que toi -- comme c'est le cas
avec register aujourd'hui -- il me semble normal qu'il le fasse.
Si ce n'est pas le cas, ce qui vaut pour 99% des compilateurs
aujourd'hui, les critères de la qualité de l'implémentation
veulent qu'il respecte tes indications. (Indications données
évidemment non seulement par la declaration, mais aussi par les
options de compilation, etc.)

La motivation derrière la différence formelle, c'est que la
plupart des compilateurs sont incapables à générer du code en
ligne si la définition de la fonction n'est pas disponible dans
l'unité de traduction. C-à-d que la motivation, c'est de rendre
l'implémentation de l'intention plus facile.

Donc, même sans option, rien ne garantit (sauf documentation
contraire du compilateur) que ce qui est indiqué inline le
sera et que ce qui ne l'est pas ne le sera pas.


Tout à fait. Avec optimisation, g++ génère en ligne des petites
fonctions dont il dispose de l'implémentation, même si elles ne
sont pas déclarée inline. En revanche, il ne génère pas (ou pas
complètement) en ligne des fonctions avec une récursion à
l'infinie, même si elles sont déclarées inline. (On se démande
bien pourquoi:-). Il me semble avoir régardé dans la passée, et
qu'il s'arrête à 40 niveaux d'indirection, ou quelque chose
comme ça.)

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34


Avatar
Patrick 'Zener' Brunet
Bonjour.

Je réponds à none" <""(none)"@(none) <""(none)"@(none)">
Quelles sont les motivations qui peuvent me pousser à utiliser des
méthodes inline ?
Par exemple, j'ai une classe avec des membres privés dont je déclare
des accesseurs (getFoo, setFoo)

public:
int getFoo() const;
void setFoo(int value);
private:
int m_foot;

Est-il judicieux de déclarer getFoo et setFoo en inline d'emblée, en
sachant que ce sont des fonctions au contenu trivial et petit (getFoo
se contente de renvoyer m_foot par exemple) ?

Merci pour vos conseils avisés


Je crois que ça dépend déjà du contexte:

* Si vous développez une librairie, il peut être intéressant de proposer à
votre utilisateur de choisir des fonctions (normalement) plus efficaces sans
lui imposer de relire le code. Si vous êtes votre propre utilisateur, vous
maîtrisez mieux les usages.

* Ensuite il y a plusieurs profils de programmeurs: certains comptent sur le
compilateur pour contrer leurs maladresses, alors que d'autres s'efforcent
de programmer à la fois fiable et efficace. Parmi les seconds, certains y
parviennent le plus souvent et d'autres se trompent.

* Enfin il y a la qualité et "l'intelligence embarquée" du compilateur:
certains sont capables de restructurer complètement le code, d'autres pas.

Donc AMHA, il n'y a pas de mal à mettre en place un maximum de précision
dans son code, pour autant qu'elle soit réfléchie, et en sachant que le
compilateur peut éventuellement la remettre en question.

Donc typiquement pour une fonction qui ainsi emballe simplement une ou deux
instructions simples,
... faisant assez peu usage de la pile pour que son coût d'invocation (en
nombre d'instructions) soit important par rapport au traitement lui-même,
... AMHA la déclaration inline est plutôt une amélioration.

Mais donc ça nécessite d'avoir une certaine connaissance du protocole normal
d'invocation sur le(s) système(s) visé(s).

Cordialement,

--
/***************************************
* Patrick BRUNET
* E-mail: lien sur http://zener131.free.fr/ContactMe
***************************************/

Avatar
Fabien LE LEZ
On 17 Mar 2006 01:12:18 -0800, "kanze" :

cette modification provoque la récompilation de tous les
utilisateurs de ta classe.


C'est pas non plus la mort, sauf peut-être si l'implémentation change
souvent, et le header est utilisé dans plusieurs centaines de modules.

Avatar
none




Merci à tout le monde, j'y vois plus clair maintenant et c'est toujours
aussi intéressant de lire ce forum.

Avatar
Bertrand Motuelle
kanze wrote:
none (none) wrote:

Quelles sont les motivations qui peuvent me pousser à utiliser
des méthodes inline ?


Le profiler a dit que ça ne va pas autrement.



C'est effectivement le conseil que j'ai lu le plus souvent à ce sujet.
Mais quelles sont les indications concrètes que le profiler peut
donner ? Il ne me semble pas que quantify, par exemple, puisse
rapporter le coût de *l'appel* d'une fonction. Doit-on se baser sur le
nombre d'appels à la fonction ?

a+,
Bertrand.


Avatar
kanze
Fabien LE LEZ wrote:
On 17 Mar 2006 01:12:18 -0800, "kanze" :

cette modification provoque la récompilation de tous les
utilisateurs de ta classe.


C'est pas non plus la mort, sauf peut-être si l'implémentation
change souvent, et le header est utilisé dans plusieurs
centaines de modules.


Ça dépend de la contexte. Chez moi, où j'ai un AMD 3000 64 bits,
sous Linux, sur des projets personnels en somme assez petits, je
n'hesite pas à faire des make clean suivi d'un rebuild complet
-- comme tu dis, ce n'est pas la mort.

Au travail, en revanche, la taille d'un projet typique se mesure
en millions de lignes de code, et on travaille sur de vieilles
Sparcs avec des fichiers montés sur un reseau surchargé. Ce qui
change tout.

Et évidemment, j'ai pris mes habitudes à une époque où les
machines et le reseau étaient nettement moins performant. Quand
le temps de compilation de chaque unité se mesure en dizaines de
secondes, on y fait attention. Si je travaille sur un
sous-ensemble avec dix modules, et que j'en modifie une, un make
qui ne récompile que la module que j'ai modifié durait peut-être
trente secondes -- si make recompile toutes les modules, j'en ai
pour plusieurs minutes. (Et dix modules, c'est un petit
sous-système. J'ai vu des cas où toucher à un en-tête changeait
un make de moins d'une minute en un make d'un quart d'heure.)

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34


1 2 3