<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>blog.freelan.org &#187; &#187; macosx</title>
	<atom:link href="https://blog.freelan.org/tag/macosx/feed/" rel="self" type="application/rss+xml" />
	<link>https://blog.freelan.org</link>
	<description>De l&#039;informatique, des octets et des poneys.</description>
	<lastBuildDate>Fri, 04 Apr 2014 17:34:59 +0000</lastBuildDate>
	<language>fr-FR</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>https://wordpress.org/?v=4.1.42</generator>
	<item>
		<title>La directive &#8220;inline&#8221; démystifiée</title>
		<link>https://blog.freelan.org/2011/01/11/la-directive-inline-demystifiee/</link>
		<comments>https://blog.freelan.org/2011/01/11/la-directive-inline-demystifiee/#comments</comments>
		<pubDate>Tue, 11 Jan 2011 14:32:54 +0000</pubDate>
		<dc:creator><![CDATA[Julien Kauffmann]]></dc:creator>
				<category><![CDATA[C++]]></category>
		<category><![CDATA[Développement]]></category>
		<category><![CDATA[inline]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[macosx]]></category>
		<category><![CDATA[unix]]></category>
		<category><![CDATA[windows]]></category>

		<guid isPermaLink="false">http://blog.freelan.org/?p=169</guid>
		<description><![CDATA[Le C++ est sans conteste l'un des langages les plus complets mais aussi les plus complexes existant dans le monde du développement en entreprise. Ses grandes flexibilité et diversité en font à la fois un langage puissant et dangereux. Il ne s'agit pas ici d'en faire une nouvelle présentation; de nombreux ouvrages lui sont déjà consacrés : qu'il s'agisse des "design patterns" ou de fonctionnalités générales, il y en a vraiment pour tous les goûts.

Cependant, j'ai décidé aujourd'hui de traiter d'un point en particulier, souvent mal perçu par les débutants et parfois même par des gens plus expérimentés : il s'agit de la directive inline.]]></description>
				<content:encoded><![CDATA[<p>Le C++ est sans conteste l&#8217;un des langages les plus complets mais aussi les plus complexes existant dans le monde du développement en entreprise. Ses grandes flexibilité et diversité en font à la fois un langage puissant et dangereux. Il ne s&#8217;agit pas ici d&#8217;en faire une nouvelle présentation; de nombreux ouvrages lui sont déjà consacrés : qu&#8217;il s&#8217;agisse des &#8220;design patterns&#8221; ou de fonctionnalités générales, il y en a vraiment pour tous les goûts.</p>
<p>Cependant, j&#8217;ai décidé aujourd&#8217;hui de traiter d&#8217;un point en particulier, souvent mal perçu par les débutants et parfois même par des gens plus expérimentés : il s&#8217;agit de la directive <strong>inline</strong>.</p>
<h1>Piqûre de rappel</h1>
<p>Avant d&#8217;avancer sur le chemin de &#8220;l&#8217;inlining&#8221;, rappelons quelques principes élémentaires du C++.</p>
<p><em>Remarque : En tant que programmeur expérimenté, vous connaissez probablement déjà tout ce qui suit. Vous devriez tout de même prendre le temps de lire cette partie pour deux raisons : la première, ça ne fait jamais de mal. Et la deuxième : si jamais j&#8217;écrivais une bêtise, vous pourriez gentiment me le faire remarquer ! <img src="https://blog.freelan.org/wp-includes/images/smilies/icon_biggrin.gif" alt=":D" class="wp-smiley" /></em></p>
<p>Le C++ est un langage <strong>compilé</strong> (par opposition à langage <strong>interprété</strong>), ce qui signifie qu&#8217;il induit la génération d&#8217;un &#8220;binaire&#8221; lors d&#8217;une phase appelée <strong>compilation</strong>. Ce binaire peut être un fichier exécutable (.exe sous Windows), une bibliothèque (.so/.a sous Unix, .lib/.dll sous Windows) ou un fichier objet intermédiaire (.o sous Unix, .obj sous Windows).</p>
<p>La phase que l&#8217;on nomme &#8220;compilation&#8221; est en fait séparée en trois étapes successives :</p>
<ol>
<li>Le prétraitement (ou &#8220;preprocessing&#8221;), qui va se charger de remplacer les différentes <strong>macros</strong> présentes dans le code par leur véritable valeur. Le résultat de ce prétraitement est passé au &#8220;compilateur&#8221;.</li>
<li>La compilation, qui transforme le code pré-traité en langage machine au sein de fichiers objets. En pratique, il y a un fichier objet généré par <em>unité de traduction</em> (ou &#8220;translation unit&#8221;).</li>
<li>L&#8217;édition des liens, qui rassemble les fichiers objets générés au sein d&#8217;une seule entité (une <em>bibliothèque dynamique</em> ou un <em>exécutable</em>). Si on a déclaré et utilisé une fonction mais que son implémentation est absente, cette étape ne passe pas.</li>
</ol>
<p><em>Remarque : Habituellement, dans le cas d&#8217;une <strong>bibliothèque statique</strong>, l&#8217;édition des liens n&#8217;est pas effectuée : il s&#8217;agit d&#8217;une simple concaténation des fichiers objets.</em></p>
<p>Les bonnes pratiques du C++ dictent ensuite que lorsque l&#8217;on écrit le code d&#8217;une classe, on place sa <strong>définition</strong> (et donc sa <strong>déclaration</strong>) dans un fichier dit &#8220;<em>header</em>&#8220;, et son <strong>implémentation</strong> dans un fichier &#8220;<em>source</em>&#8220;.</p>
<p>Il existe une règle nommée &#8220;règle de la définition unique&#8221; (ou ODR : &#8220;<a href="http://en.wikipedia.org/wiki/One_Definition_Rule">One Definition Rule</a>&#8220;) qui dit que l&#8217;on peut <strong>déclarer</strong> autant de fois que l&#8217;on veut une classe, une fonction, etc. mais qu&#8217;on ne peut la <strong>définir </strong>qu&#8217;une seule fois. Nous verrons plus tard en quoi <strong>inline</strong> influe à ce niveau.</p>
<h2>Un exemple simple</h2>
<p>Prenons un exemple tout simple avec une classe &#8220;Person&#8221; qui représente<em>&#8230;</em> une personne. <img src="https://blog.freelan.org/wp-includes/images/smilies/icon_smile.gif" alt=":)" class="wp-smiley" /></p>
<p>Voici le fichier <em>header</em> :</p><pre class="crayon-plain-tag">/**
 * \file person.hpp
 * \author Julien Kauffmann
 * \brief A person.
 */

#ifndef PERSON_HPP
#define PERSON_HPP

#include &lt;string&gt;

class Person
{
  public:

    /**
     * \brief Create a person given its name.
     * \param name The person name.
     */
    Person(const std::string&amp; name);

    /**
     * \brief Get the name.
     * \return The name.
     */
    const std::string&amp; name() const;

  private:

    /**
     * \brief The name.
     */
    std::string m_name;
};

#endif /* PERSON_HPP */</pre><p>Dans ce header, nous avons <strong>déclaré</strong> et <strong>défini</strong> le type <em>Person</em>.</p>
<p>Son implémentation, elle, va dans le fichier source :</p><pre class="crayon-plain-tag">/**
 * \file person.cpp
 * \author Julien Kauffmann
 * \brief A person.
 */

#include &quot;person.hpp&quot;

Person::Person(const std::string&amp; _name) :
  m_name(_name)
{
}

const std::string&amp; Person::name() const
{
  return m_name;
}</pre><p>Si nous reprenons les trois étapes de la compilation, voici ce que se passe pour chacun des fichiers :</p>
<p>Le processus commence par le choix de l&#8217;unité de traduction à compiler : ici, il s&#8217;agit du fichier &#8220;person.cpp&#8221;.</p>
<ul>
<li>Le préprocesseur analyse chaque ligne, procède à l&#8217;inclusion du fichier &#8220;person.hpp&#8221; (directive #include) tel qu&#8217;on le ferait avec un copier-coller. Au passage, tous les commentaires dans les fichiers sont supprimés, et les éventuelles <strong>macros</strong> sont remplacées.</li>
</ul>
<p>On se retrouve avec un fichier qui se rapproche théoriquement de ça :</p><pre class="crayon-plain-tag">// J'omets volontairement la d&eacute;finition de std::string qui est *un peu* longue !

class Person
{
  public:
    Person(const std::string&amp; name);
    const std::string&amp; name() const;

  private:
    std::string m_name;
};

Person::Person(const std::string&amp; _name) :
  m_name(_name)
{
}

const std::string&amp; Person::name() const
{
  return m_name;
}</pre><p></p>
<ul>
<li>Le compilateur vérifie la syntaxe de l&#8217;ensemble du fichier et compile chaque implémentation de fonction (ou méthode) qu&#8217;il rencontre. Ici, les codes du constructeur Person::Person() et du &#8220;getter&#8221; name() sont effectivement transformés en langage machine au sein d&#8217;un fichier objet.</li>
<li>Enfin, si le programme fait référence à Person::Person() ou Person::name(), l&#8217;édition des liens associera l&#8217;appel de fonction à son adresse effective.</li>
</ul>
<h1>Les idées fausses sur la directive &#8220;inline&#8221;</h1>
<p>S&#8217;en suit ici un florilège des idées reçues que j&#8217;ai déjà entendu (ou prononcé :D) ça et là sur <strong>inline</strong> :</p>
<ul>
<li>&#8220;Ça sert à ordonner au compilateur de ne jamais compiler le code de la fonction.&#8221;</li>
<li>&#8220;C&#8217;est quand on écrit directement du code dans la définition d&#8217;une classe.&#8221;</li>
<li>&#8220;C&#8217;est pour accélérer les appels à une fonction.&#8221;</li>
<li>&#8220;Ça sert à déclarer des macros intelligentes.&#8221;</li>
<li>&#8220;Ça indique que la fonction a une liaison interne.&#8221;</li>
</ul>
<p>En réalité, voici la raison d&#8217;être du mot clé <strong>inline</strong>, telle que définie par <em><a href="http://fr.wikipedia.org/wiki/Bjarne_Stroustrup">Bjarne  Stroustrup</a></em> :</p>
<blockquote><p>The <code>inline</code> specifier is a hint to the compiler that it  should attempt to generate code for a call of the inline  function rather than laying down the code for the function once and then calling  through the usual function call mechanism.</p></blockquote>
<p>Pour ceux que l&#8217;anglais rebute :</p>
<blockquote><p>La directive <code>inline</code> est une information donnée au compilateur lui indiquant qu&#8217;il devrait essayer de générer du code pour chaque appel de la fonction plutôt que de générer une seule fois le code de façon générique et d&#8217;utiliser le mécanisme habituel d&#8217;appel de fonction.</p></blockquote>
<p>En gros, on apprend que la directive <strong>inline</strong> n&#8217;est <em>pas un ordre</em>, mais une simple <strong>indication</strong>, que le compilateur est d&#8217;ailleurs libre de refuser. Souvenez-vous que c&#8217;est son travail d&#8217;optimiser le code généré, pas le vôtre.</p>
<p>En pratique, on utilisera donc pas <strong>inline</strong> pour des raisons d&#8217;optimisation, mais simplement pour modifier la &#8220;One Definition Rule&#8221;. En effet, là où une fonction ne doit habituellement avoir <strong>qu&#8217;une seule définition</strong> parmi <em>toutes</em> les unités de traductions, le fait de la rendre<strong> inline</strong> change la règle et indique que la fonction <strong>doit avoir la même définition</strong> dans <em>chacune</em> des unités de traduction qui l&#8217;utilise.</p>
<h2>Un exemple</h2>
<p>Prenons pour exemple le célèbre cas de la fonction factorielle.</p>
<p><em>Remarque : Le choix de cet exemple n&#8217;est pas innocent. <a href="http://fr.wikipedia.org/wiki/Bjarne_Stroustrup">Bjarne Stroustrup</a> utilise lui-même cet exemple lorsqu&#8217;il parle de la directive <strong>inline</strong>.</em></p>
<p>Une implémentation naïve de factorielle est la suivante :</p><pre class="crayon-plain-tag">inline int factorial(int n)
{
 return (n &lt; 2) ? 1 : n * factorial(n - 1);
}</pre><p><em>Note : Cette fonction n&#8217;est pas optimale (on répète inutilement le test &#8220;(n <= 1)" à chaque itération. Mais elle convient très bien pour notre exemple.
</em></p>
<p>Supposons que cette fonction est déclarée dans un header de notre bibliothèque et qu&#8217;un utilisateur de cette bibliothèque utilise quelque-part dans son code la fonction, par exemple :</p><pre class="crayon-plain-tag">int main()
{
  int f = factorial(6);
  std::cout &lt;&lt; &quot;Factorial(6) = &quot; &lt;&lt; f &lt;&lt; std::endl;
  return EXIT_SUCCESS;
}</pre><p>Lors de la compilation de ce code, il peut se passer plusieurs choses :</p>
<ol>
<li>Le compilateur peut décider de compiler la fonction <em>factorial</em> comme n&#8217;importe qu&#8217;elle autre fonction. Elle aura en pratique un passage de paramètre, une pile d&#8217;appel etc.</li>
<li>Ou il peut décider de remplacer <em>factorial(6)</em> par <em>6 * factorial(5)</em> directement.</li>
<li>Enfin, un compilateur très intelligent peut carrément décider &#8220;d&#8217;inliner&#8221; complètement l&#8217;appel et de remplacer <em>factorial(6)</em> par <em>720</em>, optimisant de ce fait drastiquement le programme.</li>
</ol>
<p>On notera que l&#8217;appel d&#8217;une fonction <strong>inline</strong> est sémantiquement identique à celle d&#8217;une fonction &#8220;classique&#8221;. Il est possible d&#8217;en hériter, de la surcharger, etc.</p>
<h1>Utilisation au quotidien</h1>
<p>Voici quelques usages corrects de fonctions &#8220;<strong>inline</strong>&#8221; :</p><pre class="crayon-plain-tag">namespace Foo
{
	class Bar
	{
		public:

			int value() const { return m_value; }

			int add(int a) const;

			template
			T sub(T a)
			{
				return m_value - a;
			}

		private:

			int m_value;
	};

	inline Bar::add(int a) const { return m_value + a; }
}</pre><p></p>
<ul>
<li>Dans le premier cas, la méthode value() est directement définie au sein de la définition de la classe. Elle est <em>implicitement</em> déclarée <strong>inline</strong>. L&#8217;ajout du mot clé <strong>inline</strong> serait <em>redondant</em> et donc inutile.</li>
<li>Dans le second cas, la méthode add() est simplement déclarée (sans mot clé particulier) au sein de la classe. Sa définition est écrite dans le fichier <em>header</em>, en dehors de celle de la classe, mais toujours dans le même <em>namespace</em>, tel qu&#8217;on le ferait si on implémentait cette fonction dans le fichier source. Dans ce cas, la <strong>définition</strong> de la fonction étant écrite au sein même du fichier header (et donc potentiellement présente dans plusieurs unités de traduction), on <strong>doit</strong> cependant ajouter le mot clé <strong>inline</strong> pour s&#8217;affranchir de la &#8220;<em>One Definition Rule</em>&#8220;.</li>
<li>Enfin, dans le dernier cas, la méthode sub n&#8217;est pas une vraie méthode mais un template. L&#8217;ajout de la directive <strong>inline</strong> n&#8217;est <em>pas obligatoire</em>, car encore une fois, la définition de la méthode se situe dans la définition de la classe. Elle est donc implicitement <strong>inline</strong>.</li>
</ul>
<p>N&#8217;utilisez <strong>inline</strong> que sur de très petites fonctions (notion subjective mais en gros : si votre fonction fait plus qu&#8217;une simple opération arithmétique ou un retour de valeur, elle n&#8217;a surement pas d&#8217;intérêt à être <strong>inline</strong>) et si possible, uniquement sur celles qui ont vocation à être appelées souvent. Les meilleurs candidats pour <strong>inline</strong> sont généralement bien sûr les <em>getters</em>, les <em>setters</em>, ou encore les <em>destructeurs virtuels vides</em>.</p>
<h1>Conclusion</h1>
<p>La première fois que l&#8217;on m&#8217;a parlé du mot clef <strong>inline</strong>, on me l&#8217;a présenté comme un moyen d&#8217;optimiser les appels de fonction. Pendant très longtemps, j&#8217;ai d&#8217;ailleurs soutenu cette version aveuglement. Mais nous avons vu aujourd&#8217;hui que les compilateurs sont suffisamment capables pour déterminer d&#8217;eux-même quand, quoi et comment optimiser.</p>
<p>En pratique, on retiendra que de bonnes connaissances concernant la &#8220;One Definition Rule&#8221; et la directive <strong>inline</strong> sont indispensables à l&#8217;écriture d&#8217;un code réutilisable et maintenable.</p>
<p>J&#8217;espère que cet article vous aura appris quelque-chose (ou à défaut intéressé). N&#8217;hésitez pas à me signaler dans les commentaires les éventuelles erreurs que j&#8217;aurais pu commettre.</p>
<p><strong>Bon code !</strong></p>
]]></content:encoded>
			<wfw:commentRss>https://blog.freelan.org/2011/01/11/la-directive-inline-demystifiee/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
	</channel>
</rss>
