<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Memory Management on kenji.blog</title><link>http://kenji.blog/fr/tags/memory-management/</link><description>Recent content in Memory Management on kenji.blog</description><generator>Hugo -- gohugo.io</generator><language>fr</language><copyright>kenjinote</copyright><lastBuildDate>Sat, 12 Sep 2026 07:00:00 +0900</lastBuildDate><atom:link href="http://kenji.blog/fr/tags/memory-management/index.xml" rel="self" type="application/rss+xml"/><item><title>Guide d'utilisation des pointeurs intelligents (std::unique_ptr / shared_ptr) pour prévenir les fuites de mémoire</title><link>http://kenji.blog/fr/p/cpp-smart-pointers-guide-unique-shared-ptr/</link><pubDate>Sat, 12 Sep 2026 07:00:00 +0900</pubDate><guid>http://kenji.blog/fr/p/cpp-smart-pointers-guide-unique-shared-ptr/</guid><description>&lt;img src="http://kenji.blog/p/cpp-smart-pointers-guide-unique-shared-ptr/img/eyecatch.jpg" alt="Featured image of post Guide d'utilisation des pointeurs intelligents (std::unique_ptr / shared_ptr) pour prévenir les fuites de mémoire" />&lt;p>La gestion de la mémoire en C++ a longtemps été l&amp;rsquo;un des plus grands défis pour les développeurs. Le style traditionnel de gestion de la mémoire, qui repose sur l&amp;rsquo;utilisation manuelle de &lt;code>new&lt;/code> et &lt;code>delete&lt;/code>, a été un terrain propice pour des bugs graves tels que les fuites de mémoire, les pointeurs sauvages (dangling pointers) et les doubles libérations. Cependant, avec l&amp;rsquo;avènement du C++ moderne (depuis C++11), la situation a radicalement changé. Au cœur de cette évolution se trouvent les &amp;ldquo;pointeurs intelligents&amp;rdquo; (Smart Pointers).&lt;/p>
&lt;p>Dans cet article, nous allons expliquer de manière très détaillée le fonctionnement et l&amp;rsquo;utilisation avancée de &lt;code>std::unique_ptr&lt;/code>, &lt;code>std::shared_ptr&lt;/code> et &lt;code>std::weak_ptr&lt;/code>. Ce sont des outils puissants pour éradiquer les fuites de mémoire et réaliser une gestion sûre et efficace des ressources. Nous aborderons leur implémentation interne (blocs de contrôle et opérations atomiques), leur impact sur les performances, ainsi que la formulation mathématique du comptage de références.&lt;/p>
&lt;h2 id="1-introduction--lâge-sombre-de-la-gestion-de-la-mémoire-en-c-et-laube-du-c-moderne">1. Introduction : L&amp;rsquo;âge sombre de la gestion de la mémoire en C++ et l&amp;rsquo;aube du C++ moderne
&lt;/h2>&lt;p>Auparavant, dans le développement C++, c&amp;rsquo;était au développeur de prendre la responsabilité de libérer la mémoire allouée sur le tas (heap).&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;span class="lnt">7
&lt;/span>&lt;span class="lnt">8
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="kt">void&lt;/span> &lt;span class="nf">legacy_function&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">int&lt;/span>&lt;span class="o">*&lt;/span> &lt;span class="n">ptr&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">new&lt;/span> &lt;span class="kt">int&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">10&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// ... un certain traitement ...
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">some_condition&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="c1">// Fuite de mémoire ! delete n&amp;#39;est pas appelé
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">delete&lt;/span> &lt;span class="n">ptr&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Dans un code comme celui ci-dessus, si une exception se produit ou si un retour anticipé est effectué, &lt;code>delete&lt;/code> est ignoré, ce qui entraîne une fuite de mémoire. Le paradigme permettant d&amp;rsquo;éviter cela est appelé &amp;ldquo;RAII&amp;rdquo; (Resource Acquisition Is Initialization). Le RAII est une technique qui lie l&amp;rsquo;acquisition d&amp;rsquo;une ressource à l&amp;rsquo;initialisation d&amp;rsquo;un objet (constructeur), et la libération de la ressource à la destruction de l&amp;rsquo;objet (destructeur). Les pointeurs intelligents sont une pile de classes de la bibliothèque standard qui appliquent cet idiome RAII à la gestion de la mémoire.&lt;/p>
&lt;h2 id="2-stdunique_ptr--la-propriété-exclusive-avec-zéro-surcoût">2. &lt;code>std::unique_ptr&lt;/code> : La propriété exclusive avec zéro surcoût
&lt;/h2>&lt;p>&lt;code>std::unique_ptr&lt;/code> est un pointeur intelligent qui possède une &amp;ldquo;propriété exclusive&amp;rdquo; (Exclusive Ownership) sur un objet alloué dynamiquement. Il ne peut y avoir qu&amp;rsquo;un seul &lt;code>unique_ptr&lt;/code> possédant une ressource donnée à la fois.&lt;/p>
&lt;h3 id="21-le-principe-du-zéro-surcoût">2.1 Le principe du zéro surcoût
&lt;/h3>&lt;p>Le plus grand atout de &lt;code>std::unique_ptr&lt;/code> est sa performance. Dans son état par défaut (sans destructeur personnalisé), la taille de &lt;code>std::unique_ptr&lt;/code> est exactement la même que celle d&amp;rsquo;un pointeur brut (Raw Pointer). Il ne possède aucune variable membre inutile et n&amp;rsquo;utilise pas de fonctions virtuelles. Grâce à l&amp;rsquo;optimisation du compilateur, l&amp;rsquo;accès via &lt;code>std::unique_ptr&lt;/code> se déploie en code assembleur équivalent à celui d&amp;rsquo;un pointeur brut.&lt;/p>
&lt;h3 id="22-transfert-de-propriété-et-stdmove">2.2 Transfert de propriété et &lt;code>std::move&lt;/code>
&lt;/h3>&lt;p>Puisqu&amp;rsquo;il détient une propriété exclusive, un &lt;code>std::unique_ptr&lt;/code> ne peut pas être copié (le constructeur de copie et l&amp;rsquo;opérateur d&amp;rsquo;affectation par copie ont été supprimés avec &lt;code>delete&lt;/code>). Pour transférer la propriété à un autre &lt;code>unique_ptr&lt;/code>, vous devez utiliser la sémantique de déplacement (Move Semantics) via &lt;code>std::move&lt;/code>.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;iostream&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;memory&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">Resource&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">public&lt;/span>&lt;span class="o">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">Resource&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;Resource acquired&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s">&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">~&lt;/span>&lt;span class="n">Resource&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;Resource destroyed&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s">&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">void&lt;/span> &lt;span class="nf">do_something&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;Doing something&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s">&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">};&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kt">void&lt;/span> &lt;span class="nf">process_resource&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">unique_ptr&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">Resource&lt;/span>&lt;span class="o">&amp;gt;&lt;/span> &lt;span class="n">ptr&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">ptr&lt;/span>&lt;span class="o">-&amp;gt;&lt;/span>&lt;span class="n">do_something&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// En sortant de la portée, ptr est détruit et Resource est également libérée
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kt">int&lt;/span> &lt;span class="nf">main&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">unique_ptr&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">Resource&lt;/span>&lt;span class="o">&amp;gt;&lt;/span> &lt;span class="n">my_ptr&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">make_unique&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">Resource&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// process_resource(my_ptr); // Erreur : copie interdite
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">process_resource&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">move&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">my_ptr&lt;/span>&lt;span class="p">));&lt;/span> &lt;span class="c1">// Transfert de propriété
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="o">!&lt;/span>&lt;span class="n">my_ptr&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;my_ptr is now empty.&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s">&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Le diagramme Mermaid suivant illustre le concept du transfert de propriété par &lt;code>std::move&lt;/code>.&lt;/p>
&lt;div class="mermaid">graph LR
subgraph "Avant std::move"
A["unique_ptr (ptr1)"] -->|"Possède"| B["Mémoire Tas (Objet)"]
end
subgraph "Après std::move"
C["unique_ptr (ptr1)"] -.->|"Vide (nullptr)"| D["nullptr"]
E["unique_ptr (ptr2)"] -->|"Possède"| F["Mémoire Tas (Objet)"]
end&lt;/div>
&lt;h3 id="23-implémentation-dun-destructeur-personnalisé">2.3 Implémentation d&amp;rsquo;un destructeur personnalisé
&lt;/h3>&lt;p>Lors de l&amp;rsquo;encapsulation d&amp;rsquo;API héritées du C (comme &lt;code>FILE*&lt;/code> ou des sockets), il est nécessaire d&amp;rsquo;appeler une fonction autre que &lt;code>delete&lt;/code> (comme &lt;code>fclose&lt;/code>) pour libérer la mémoire. Il est possible de spécifier un destructeur personnalisé (custom deleter) comme deuxième argument de modèle (template argument) pour &lt;code>std::unique_ptr&lt;/code>.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;cstdio&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;memory&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// Foncteur pour le destructeur personnalisé
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="k">struct&lt;/span> &lt;span class="nc">FileDeleter&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">void&lt;/span> &lt;span class="nf">operator&lt;/span>&lt;span class="p">()(&lt;/span>&lt;span class="n">FILE&lt;/span>&lt;span class="o">*&lt;/span> &lt;span class="n">fp&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">const&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">fp&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;Closing file.&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s">&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">fclose&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">fp&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">};&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">using&lt;/span> &lt;span class="n">UniqueFile&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">unique_ptr&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">FILE&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">FileDeleter&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kt">int&lt;/span> &lt;span class="nf">main&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">UniqueFile&lt;/span> &lt;span class="n">file&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">fopen&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;test.txt&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s">&amp;#34;w&amp;#34;&lt;/span>&lt;span class="p">));&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">file&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">fputs&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;Hello, Smart Pointers!&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">file&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">());&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// FileDeleter est appelé et fclose est exécuté à la fin de la portée
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">return&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>L&amp;rsquo;utilisation de pointeurs de fonction ou d&amp;rsquo;expressions lambda comme destructeurs personnalisés peut augmenter la taille du &lt;code>unique_ptr&lt;/code>. Cependant, l&amp;rsquo;utilisation d&amp;rsquo;un objet fonctionnel (Functor) sans état, comme illustré ci-dessus, permet de ne pas augmenter la taille par rapport à un pointeur brut grâce à l&amp;rsquo;&lt;strong>EBCO (Empty Base Class Optimization)&lt;/strong> en C++ ou à &lt;code>[[no_unique_address]]&lt;/code> en C++20 (le zéro surcoût est ainsi maintenu).&lt;/p>
&lt;h2 id="3-stdshared_ptr--propriété-partagée-et-bloc-de-contrôle">3. &lt;code>std::shared_ptr&lt;/code> : Propriété partagée et bloc de contrôle
&lt;/h2>&lt;p>&lt;code>std::shared_ptr&lt;/code> est un pointeur intelligent qui permet à plusieurs pointeurs de partager la propriété du même objet. L&amp;rsquo;objet géré est libéré lorsque le dernier &lt;code>shared_ptr&lt;/code> est détruit.&lt;/p>
&lt;h3 id="31-architecture-interne--le-bloc-de-contrôle">3.1 Architecture interne : Le bloc de contrôle
&lt;/h3>&lt;p>Outre le pointeur vers l&amp;rsquo;objet géré, &lt;code>std::shared_ptr&lt;/code> alloue et partage sur le tas des métadonnées appelées &lt;strong>bloc de contrôle (Control Block)&lt;/strong>. Ce bloc de contrôle contient les informations suivantes :&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Strong Count (Compteur fort)&lt;/strong> : Le nombre de &lt;code>shared_ptr&lt;/code> qui possèdent l&amp;rsquo;objet. Lorsque ce nombre tombe à 0, l&amp;rsquo;objet est détruit.&lt;/li>
&lt;li>&lt;strong>Weak Count (Compteur faible)&lt;/strong> : Le nombre de &lt;code>weak_ptr&lt;/code> qui surveillent l&amp;rsquo;objet. Lorsque le Strong Count et le Weak Count tombent tous les deux à 0, le bloc de contrôle lui-même est libéré.&lt;/li>
&lt;li>&lt;strong>Destructeur personnalisé et allocateur&lt;/strong> (s&amp;rsquo;ils sont spécifiés).&lt;/li>
&lt;/ol>
&lt;div class="mermaid">graph TD
A["std::shared_ptr&lt;T> (sp1)"] -->|"Pointeur vers T"| B["Objet géré (T)"]
A -->|"Pointeur vers le bloc de contrôle"| C["Bloc de contrôle"]
D["std::shared_ptr&lt;T> (sp2)"] -->|"Pointeur vers T"| B
D -->|"Pointeur vers le bloc de contrôle"| C
C -->|"Détruit"| B
C -.->|"Strong Count : 2"| E["Compteur fort (Strong Count)"]
C -.->|"Weak Count : 0"| F["Compteur faible (Weak Count)"]
C -.->|"Destructeur personnalisé"| G["Destructeur (Deleter)"]&lt;/div>
&lt;p>Pour cette raison, la taille de l&amp;rsquo;objet &lt;code>std::shared_ptr&lt;/code> lui-même est généralement le double de celle d&amp;rsquo;un pointeur brut (un pointeur vers l&amp;rsquo;objet, et un pointeur vers le bloc de contrôle).&lt;/p>
&lt;h3 id="32-performances-et-opérations-atomiques">3.2 Performances et opérations atomiques
&lt;/h3>&lt;p>Les compteurs de références dans le bloc de contrôle sont implémentés en tant qu&amp;rsquo;&lt;strong>opérations atomiques (Atomic Operations)&lt;/strong> afin qu&amp;rsquo;ils puissent être incrémentés et décrémentés en toute sécurité, même dans un environnement multithread.&lt;/p>
&lt;p>Sur les architectures x86/x64, des instructions atomiques comme &lt;code>lock xadd&lt;/code> sont utilisées pour modifier les compteurs de références. Cela implique un surcoût de plusieurs dizaines de cycles par rapport à une simple addition d&amp;rsquo;entiers. Par conséquent, passer un &lt;code>shared_ptr&lt;/code> par valeur à une fonction entraîne des incrémentations et décrémentations atomiques à chaque copie, ce qui dégrade les performances.&lt;/p>
&lt;p>&lt;strong>Bonnes pratiques&lt;/strong> : Lorsque vous passez un &lt;code>shared_ptr&lt;/code> à une fonction, sauf s&amp;rsquo;il est nécessaire de partager la propriété, vous devez le passer en tant que &lt;code>const std::shared_ptr&amp;lt;T&amp;gt;&amp;amp;&lt;/code> (référence constante), ou bien passer un pointeur brut / une référence.&lt;/p>
&lt;h3 id="33-stdmake_shared-vs-new">3.3 &lt;code>std::make_shared&lt;/code> vs &lt;code>new&lt;/code>
&lt;/h3>&lt;p>Lors de la création d&amp;rsquo;un &lt;code>shared_ptr&lt;/code>, vous devez utiliser &lt;code>std::make_shared&lt;/code> dans la mesure du possible. Il y a deux raisons majeures à cela :&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Optimisation de l&amp;rsquo;allocation mémoire&lt;/strong> :
L&amp;rsquo;utilisation de &lt;code>new&lt;/code> entraîne deux allocations sur le tas : l&amp;rsquo;allocation du corps de l&amp;rsquo;objet et l&amp;rsquo;allocation du bloc de contrôle. L&amp;rsquo;utilisation de &lt;code>std::make_shared&lt;/code> permet d&amp;rsquo;allouer un seul grand bloc de mémoire contenant les deux en une seule allocation sur le tas, ce qui améliore également l&amp;rsquo;efficacité du cache.&lt;/li>
&lt;li>&lt;strong>Sécurité des exceptions (Exception Safety)&lt;/strong> :
Dans les normes antérieures à C++17, l&amp;rsquo;ordre d&amp;rsquo;évaluation des arguments d&amp;rsquo;une fonction n&amp;rsquo;était pas spécifié. Ainsi, si une exception se produisait lors de l&amp;rsquo;évaluation d&amp;rsquo;un autre argument avant que le pointeur alloué par &lt;code>new&lt;/code> ne soit passé au constructeur du &lt;code>shared_ptr&lt;/code>, il y avait un risque de fuite de mémoire. &lt;code>make_shared&lt;/code> évite complètement ce problème.&lt;/li>
&lt;/ol>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// Pratique à éviter (2 allocations mémoire)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">shared_ptr&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">MyClass&lt;/span>&lt;span class="o">&amp;gt;&lt;/span> &lt;span class="n">ptr1&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="k">new&lt;/span> &lt;span class="n">MyClass&lt;/span>&lt;span class="p">());&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// Pratique recommandée (1 allocation mémoire)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">shared_ptr&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">MyClass&lt;/span>&lt;span class="o">&amp;gt;&lt;/span> &lt;span class="n">ptr2&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">make_shared&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">MyClass&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h2 id="4-stdweak_ptr--résolution-des-références-circulaires-et-surveillance">4. &lt;code>std::weak_ptr&lt;/code> : Résolution des références circulaires et surveillance
&lt;/h2>&lt;p>La propriété partagée présente une faille critique appelée &amp;ldquo;références circulaires (Circular References)&amp;rdquo;. Si un objet A et un objet B se pointent mutuellement via des &lt;code>shared_ptr&lt;/code>, leurs Strong Counts respectifs seront maintenus au moins à 1 et ne tomberont jamais à 0 avant la fin du programme, ce qui provoquera une fuite de mémoire.&lt;/p>
&lt;div class="mermaid">graph TD
subgraph "Référence circulaire (Fuite de mémoire)"
A["Objet A"] -->|"shared_ptr (Strong=1)"| B["Objet B"]
B -->|"shared_ptr (Strong=1)"| A
end&lt;/div>
&lt;h3 id="41-briser-le-cycle-avec-stdweak_ptr">4.1 Briser le cycle avec &lt;code>std::weak_ptr&lt;/code>
&lt;/h3>&lt;p>La solution à ce problème est &lt;code>std::weak_ptr&lt;/code>. Un &lt;code>weak_ptr&lt;/code> est créé à partir d&amp;rsquo;un &lt;code>shared_ptr&lt;/code> et fait référence à un objet, mais il &lt;strong>n&amp;rsquo;augmente pas le Strong Count&lt;/strong>. À la place, il augmente le Weak Count. Cela permet de &amp;ldquo;surveiller&amp;rdquo; un objet sans en prendre la propriété.&lt;/p>
&lt;div class="mermaid">graph TD
subgraph "Briser la référence circulaire"
C["Objet A"] -->|"shared_ptr (Strong=1)"| D["Objet B"]
D -.->|"weak_ptr (Weak=1)"| C
end&lt;/div>
&lt;h3 id="42-accès-sécurisé-avec-la-méthode-lock">4.2 Accès sécurisé avec la méthode &lt;code>lock()&lt;/code>
&lt;/h3>&lt;p>&lt;code>weak_ptr&lt;/code> ne possède pas d&amp;rsquo;opérateurs pour accéder directement à l&amp;rsquo;objet (&lt;code>-&amp;gt;&lt;/code> ou &lt;code>*&lt;/code>). C&amp;rsquo;est parce que l&amp;rsquo;objet cible peut avoir déjà été détruit. Pour y accéder en toute sécurité, appelez la méthode &lt;code>lock()&lt;/code> pour obtenir temporairement un &lt;code>shared_ptr&lt;/code>.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;iostream&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;memory&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">Node&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">public&lt;/span>&lt;span class="o">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">string&lt;/span> &lt;span class="n">name&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">shared_ptr&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">Node&lt;/span>&lt;span class="o">&amp;gt;&lt;/span> &lt;span class="n">next&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">weak_ptr&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">Node&lt;/span>&lt;span class="o">&amp;gt;&lt;/span> &lt;span class="n">prev&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="c1">// Utilisation de weak_ptr pour éviter la référence circulaire
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">Node&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="k">const&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">string&lt;/span>&lt;span class="o">&amp;amp;&lt;/span> &lt;span class="n">n&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">:&lt;/span> &lt;span class="n">name&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">n&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;Created &amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">name&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s">&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">~&lt;/span>&lt;span class="n">Node&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;Destroyed &amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">name&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s">&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">};&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kt">int&lt;/span> &lt;span class="nf">main&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">auto&lt;/span> &lt;span class="n">nodeA&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">make_shared&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">Node&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;A&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">auto&lt;/span> &lt;span class="n">nodeB&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">make_shared&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">Node&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;B&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">nodeA&lt;/span>&lt;span class="o">-&amp;gt;&lt;/span>&lt;span class="n">next&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">nodeB&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">nodeB&lt;/span>&lt;span class="o">-&amp;gt;&lt;/span>&lt;span class="n">prev&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">nodeA&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Obtention du shared_ptr à partir du weak_ptr pour l&amp;#39;accès
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="k">auto&lt;/span> &lt;span class="n">locked_prev&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">nodeB&lt;/span>&lt;span class="o">-&amp;gt;&lt;/span>&lt;span class="n">prev&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">lock&lt;/span>&lt;span class="p">())&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;Node B&amp;#39;s prev is &amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">locked_prev&lt;/span>&lt;span class="o">-&amp;gt;&lt;/span>&lt;span class="n">name&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s">&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span> &lt;span class="k">else&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;Node B&amp;#39;s prev is already destroyed.&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s">&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="c1">// nodeA et nodeB sont correctement détruits
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h2 id="5-contraintes-de-la-propriété-partagée-dans-un-environnement-multithread">5. Contraintes de la propriété partagée dans un environnement multithread
&lt;/h2>&lt;p>La sécurité des threads (thread safety) de &lt;code>shared_ptr&lt;/code> est souvent mal comprise. &amp;ldquo;La mise à jour des compteurs de références dans le bloc de contrôle est thread-safe&amp;rdquo;, mais &amp;ldquo;la lecture et l&amp;rsquo;écriture de l&amp;rsquo;objet &lt;code>shared_ptr&lt;/code> lui-même ne sont pas thread-safe&amp;rdquo;.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Opération sûre&lt;/strong> : Plusieurs threads lisant ou écrivant, &lt;em>chacun sur sa propre&lt;/em> instance de &lt;code>shared_ptr&lt;/code> (bien qu&amp;rsquo;ils partagent le même bloc de contrôle).&lt;/li>
&lt;li>&lt;strong>Course aux données (Danger)&lt;/strong> : Plusieurs threads lisant ou écrivant simultanément sur &lt;em>exactement la même&lt;/em> instance de &lt;code>shared_ptr&lt;/code>.&lt;/li>
&lt;/ul>
&lt;p>Si une même instance doit être partagée par plusieurs threads, il faut utiliser &lt;code>std::atomic&amp;lt;std::shared_ptr&amp;lt;T&amp;gt;&amp;gt;&lt;/code> (C++20) ou la protéger avec un mutex (&lt;code>std::mutex&lt;/code>).&lt;/p>
&lt;h2 id="6-formulation-mathématique-du-comptage-de-références">6. Formulation mathématique du comptage de références
&lt;/h2>&lt;p>Les transitions d&amp;rsquo;état du cycle de vie dans le bloc de contrôle peuvent s&amp;rsquo;exprimer mathématiquement comme suit.
Soit $S(t)$ le Strong Count et $W(t)$ le Weak Count au temps $t$.&lt;/p>
&lt;p>État initial (juste après &lt;code>make_shared&lt;/code>) :
&lt;/p>
$$ S(0) = 1, \quad W(0) = 0 $$
&lt;p>Lorsqu&amp;rsquo;une copie (duplication du &lt;code>shared_ptr&lt;/code>) est effectuée :
&lt;/p>
$$ S(t_{next}) = S(t) + 1 $$
&lt;p>Condition de destruction de l&amp;rsquo;objet géré (Managed Object) :
&lt;/p>
$$ \lim_{t \to t_d} S(t) = 0 $$
&lt;p>Condition de libération en mémoire du bloc de contrôle (Control Block) lui-même :
&lt;/p>
$$ S(t) = 0 \quad \land \quad W(t) = 0 $$
&lt;p>
C&amp;rsquo;est-à-dire :
&lt;/p>
$$ S(t) + W(t) = 0 $$
&lt;p>Comme le montrent ces formules, tant qu&amp;rsquo;un &lt;code>weak_ptr&lt;/code> continue d&amp;rsquo;exister ($W(t) > 0$), l&amp;rsquo;espace mémoire restreint alloué au bloc de contrôle reste réservé même si l&amp;rsquo;objet géré a été détruit. Cela peut être considéré comme le seul inconvénient de &lt;code>make_shared&lt;/code> dans certains cas (puisque la mémoire de l&amp;rsquo;objet géré et le bloc de contrôle sont fusionnés, si une référence faible subsiste, le grand espace mémoire alloué à l&amp;rsquo;objet géré n&amp;rsquo;est pas non plus rendu au système). Cependant, en général, les avantages en termes de performances de &lt;code>make_shared&lt;/code> l&amp;rsquo;emportent largement.&lt;/p>
&lt;h2 id="7-conclusion">7. Conclusion
&lt;/h2>&lt;p>La gestion de la mémoire en C++ moderne n&amp;rsquo;est plus à l&amp;rsquo;ère de l&amp;rsquo;utilisation manuelle de &lt;code>new&lt;/code> et &lt;code>delete&lt;/code>.&lt;/p>
&lt;ol>
&lt;li>Par défaut, utilisez toujours &lt;strong>&lt;code>std::unique_ptr&lt;/code>&lt;/strong> pour bénéficier de l&amp;rsquo;absence de surcoût (zéro surcoût) tout en intégrant une propriété claire dans la conception.&lt;/li>
&lt;li>Utilisez &lt;strong>&lt;code>std::shared_ptr&lt;/code>&lt;/strong> uniquement s&amp;rsquo;il est véritablement nécessaire de partager le cycle de vie entre plusieurs propriétaires, et utilisez &lt;code>std::make_shared&lt;/code> pour le créer.&lt;/li>
&lt;li>Pour l&amp;rsquo;implémentation de structures de données ou du modèle observateur où des cycles de partage (références circulaires) peuvent se produire, utilisez &lt;strong>&lt;code>std::weak_ptr&lt;/code>&lt;/strong> pour éviter les fuites de mémoire.&lt;/li>
&lt;/ol>
&lt;p>En comprenant profondément les pointeurs intelligents et en les utilisant à bon escient, il est possible de construire des architectures logicielles sûres et robustes sans sacrifier la performance du C++.&lt;/p></description></item></channel></rss>