<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Pointers on kenji.blog</title><link>http://kenji.blog/fr/tags/pointers/</link><description>Recent content in Pointers on kenji.blog</description><generator>Hugo -- gohugo.io</generator><language>fr</language><copyright>kenjinote</copyright><lastBuildDate>Sat, 12 Sep 2026 04:00:00 +0900</lastBuildDate><atom:link href="http://kenji.blog/fr/tags/pointers/index.xml" rel="self" type="application/rss+xml"/><item><title>Explication de la 'Possession' et de 'l'Emprunt' de Rust comparés aux pointeurs C++</title><link>http://kenji.blog/fr/p/rust-ownership-borrowing-cpp-pointer-comparison/</link><pubDate>Sat, 12 Sep 2026 04:00:00 +0900</pubDate><guid>http://kenji.blog/fr/p/rust-ownership-borrowing-cpp-pointer-comparison/</guid><description>&lt;img src="http://kenji.blog/p/rust-ownership-borrowing-cpp-pointer-comparison/img/eyecatch.jpg" alt="Featured image of post Explication de la 'Possession' et de 'l'Emprunt' de Rust comparés aux pointeurs C++" />&lt;p>Dans la programmation système moderne, concilier performances et sécurité de la mémoire est un défi éternel. C++ règne en maître dans ce domaine depuis de nombreuses années, mais Rust menace récemment cette position. La principale caractéristique de Rust réside dans les concepts de « Possession » (Ownership) et d&amp;rsquo;« Emprunt » (Borrowing), qui garantissent la sécurité de la mémoire à la compilation sans avoir recours à un ramasse-miettes (Garbage Collection - GC).&lt;/p>
&lt;p>Dans cet article, nous comparerons en détail les pointeurs C++ (pointeurs bruts, &lt;code>std::unique_ptr&lt;/code>, &lt;code>std::shared_ptr&lt;/code>) avec le modèle de possession de Rust, et nous expliquerons de manière approfondie comment le compilateur de Rust (le Borrow Checker ou vérificateur d&amp;rsquo;emprunts) prévient les problèmes de type Use-After-Free (utilisation après libération) et de Data Race (accès concurrent aux données), à l&amp;rsquo;aide d&amp;rsquo;exemples de code et de diagrammes.&lt;/p>
&lt;h2 id="1-les-bases-de-la-gestion-de-la-mémoire--pile-stack-et-tas-heap">1. Les bases de la gestion de la mémoire : Pile (Stack) et Tas (Heap)
&lt;/h2>&lt;p>Pour comprendre les bases de la gestion de la mémoire, revoyons d&amp;rsquo;abord comment un programme utilise la mémoire. L&amp;rsquo;espace mémoire est principalement divisé en « Pile » (Stack) et « Tas » (Heap).&lt;/p>
&lt;h3 id="pile-stack">Pile (Stack)
&lt;/h3>&lt;p>C&amp;rsquo;est la zone où sont stockées les variables locales lors des appels de fonctions. Elle possède une structure LIFO (Dernier Entré, Premier Sorti), et l&amp;rsquo;allocation ainsi que la libération de la mémoire sont extrêmement rapides. Seules les données dont la taille peut être déterminée à la compilation y sont placées.&lt;/p>
&lt;h3 id="tas-heap">Tas (Heap)
&lt;/h3>&lt;p>C&amp;rsquo;est là que sont placées les données dont la taille est déterminée dynamiquement à l&amp;rsquo;exécution, ou les données qui doivent survivre au-delà de la portée d&amp;rsquo;une fonction. L&amp;rsquo;accès s&amp;rsquo;y fait par le biais de pointeurs (ou références).&lt;/p>
&lt;p>Dans les langages sans ramasse-miettes comme C++ et Rust, le coût de gestion de la mémoire du tas peut être modélisé par l&amp;rsquo;équation suivante. Si le nombre total d&amp;rsquo;objets est $N$, le temps moyen d&amp;rsquo;allocation est $T_{alloc}$, et le temps moyen de libération est $T_{dealloc}$, alors le coût total de la gestion de la mémoire $C_{memory}$ est :&lt;/p>
$$ C_{memory} = \sum_{i=1}^{N} (T_{alloc, i} + T_{dealloc, i}) + O_{sync} $$
&lt;p>Ici, $O_{sync}$ représente le surcoût de l&amp;rsquo;exclusion mutuelle (mutex ou opérations atomiques) dans un environnement multithread. Comme Rust détermine le moment de la libération de la mémoire à la compilation, il élimine la baisse de débit (Stop-The-World) due au ramasse-miettes à l&amp;rsquo;exécution, tout en exécutant $T_{dealloc}$ à un moment sûr et certain.&lt;/p>
&lt;div class="mermaid">graph TD
A["Mémoire du programme"] --> B["Pile (Rapide, Taille fixe)"]
A --> C["Tas (Dynamique, Plus lent)"]
B --> D["Variables locales"]
B --> E["Pointeurs/Références"]
C --> F["Données allouées dynamiquement"]
E -.->|"Pointe vers"| F&lt;/div>
&lt;h2 id="2-les-pointeurs-c--le-compromis-entre-liberté-et-danger">2. Les pointeurs C++ : Le compromis entre liberté et danger
&lt;/h2>&lt;p>Examinons l&amp;rsquo;évolution de la gestion de la mémoire en C++.&lt;/p>
&lt;h3 id="lère-des-pointeurs-bruts-raw-pointers-et-leurs-problèmes">L&amp;rsquo;ère des pointeurs bruts (Raw Pointers) et leurs problèmes
&lt;/h3>&lt;p>Les pointeurs bruts (&lt;code>*&lt;/code>) hérités du langage C offrent une liberté ultime, mais sont en même temps un nid à bugs graves :&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Fuite de mémoire (Memory Leak)&lt;/strong> : Oublier de faire un &lt;code>delete&lt;/code> sur une mémoire allouée avec &lt;code>new&lt;/code>.&lt;/li>
&lt;li>&lt;strong>Pointeur fantôme (Dangling Pointer)&lt;/strong> : Accéder à un pointeur après que la mémoire a été libérée (après &lt;code>delete&lt;/code>).&lt;/li>
&lt;li>&lt;strong>Double libération (Double Free)&lt;/strong> : Faire un &lt;code>delete&lt;/code> deux fois sur la même zone mémoire.&lt;/li>
&lt;/ul>
&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;/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">// C++ : Exemple de problèmes avec les pointeurs bruts
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="kt">void&lt;/span> &lt;span class="nf">rawPointerExample&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">// ... divers traitements ...
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &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>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Accès accidentel par la suite (Use-After-Free / Dangling Pointer)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="c1">// Le compilateur C++ ne peut pas faire de ceci une erreur de compilation
&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">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="o">*&lt;/span>&lt;span class="n">ptr&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">endl&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="c1">// Comportement indéfini (Undefined Behavior)
&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;h3 id="lapparition-de-raii-et-des-pointeurs-intelligents-depuis-c11">L&amp;rsquo;apparition de RAII et des pointeurs intelligents (Depuis C++11)
&lt;/h3>&lt;p>Depuis C++11, les pointeurs intelligents basés sur le concept RAII (Resource Acquisition Is Initialization) ont été standardisés, et l&amp;rsquo;utilisation directe de pointeurs bruts est devenue obsolète.&lt;/p>
&lt;h4 id="stdunique_ptr">&lt;code>std::unique_ptr&lt;/code>
&lt;/h4>&lt;p>C&amp;rsquo;est un pointeur qui exprime une possession unique. Lorsque le pointeur sort de la portée, la mémoire est automatiquement libérée. Il ne peut pas être copié, seule la « possession » peut être déplacée (en utilisant &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;/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">// C++ : std::unique_ptr
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&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">#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">&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">uniquePtrExample&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="kt">int&lt;/span>&lt;span class="o">&amp;gt;&lt;/span> &lt;span class="n">p1&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="kt">int&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">42&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// std::unique_ptr&amp;lt;int&amp;gt; p2 = p1; // Erreur de compilation (copie impossible)
&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">unique_ptr&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="kt">int&lt;/span>&lt;span class="o">&amp;gt;&lt;/span> &lt;span class="n">p3&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">move&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">p1&lt;/span>&lt;span class="p">);&lt;/span> &lt;span class="c1">// Déplacement de la possession
&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="c1">// Le point faible de C++ : p1 devient nullptr après le déplacement, mais l&amp;#39;accès lui-même est compilable
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="c1">// Provoque un plantage (erreur de segmentation) à l&amp;#39;exécution
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="c1">// std::cout &amp;lt;&amp;lt; *p1 &amp;lt;&amp;lt; std::endl;
&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;h4 id="stdshared_ptr">&lt;code>std::shared_ptr&lt;/code>
&lt;/h4>&lt;p>C&amp;rsquo;est un pointeur qui permet à plusieurs pointeurs de partager le même objet. Il utilise un compteur de références (Reference Counting) et libère la mémoire lorsque le compteur atteint 0. Les opérations d&amp;rsquo;incrémentation et de décrémentation devant être atomiques, cela entraîne un léger surcoût de performance (équivalent à $O_{sync}$ mentionné précédemment).&lt;/p>
&lt;h2 id="3-la-possession-ownership-dans-rust--un-changement-de-paradigme">3. La possession (Ownership) dans Rust : Un changement de paradigme
&lt;/h2>&lt;p>Rust a intégré le concept de &lt;code>std::unique_ptr&lt;/code> du C++ au cœur des spécifications de son langage et l&amp;rsquo;a rendu plus strict avec le « modèle de possession ».&lt;/p>
&lt;h3 id="les-3-règles-de-la-possession">Les 3 règles de la possession
&lt;/h3>&lt;p>Le système de possession de Rust repose sur les 3 règles extrêmement simples suivantes :&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Chaque valeur en Rust possède une variable qui en est le propriétaire (owner).&lt;/strong>&lt;/li>
&lt;li>&lt;strong>Il ne peut y avoir qu&amp;rsquo;un seul propriétaire à la fois.&lt;/strong>&lt;/li>
&lt;li>&lt;strong>Lorsque le propriétaire sort de la portée, la valeur est détruite.&lt;/strong>&lt;/li>
&lt;/ol>
&lt;p>Dans Rust, par défaut, les ressources sont « déplacées » (moved). Même sans spécifier explicitement quelque chose comme &lt;code>std::move&lt;/code> en C++, la possession est déplacée par l&amp;rsquo;opération d&amp;rsquo;affectation.&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-rust" data-lang="rust">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// Rust : Déplacement (move) de la possession
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="k">fn&lt;/span> &lt;span class="nf">main&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">let&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">s1&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nb">String&lt;/span>::&lt;span class="n">from&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;hello&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c1">// Données allouées sur le tas
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">let&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">s2&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">s1&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c1">// La possession est déplacée de s1 vers s2 (move)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">// La plus grande différence avec C++ : accéder à une variable après son déplacement devient une « erreur de compilation » !
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c1">// println!(&amp;#34;{}, world!&amp;#34;, s1); // Erreur de compilation : value borrowed here after move
&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 class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Cette fonctionnalité rendant « impossible à la compilation d&amp;rsquo;accéder à une variable après son déplacement » est l&amp;rsquo;une des raisons pour lesquelles Rust est plus sûr que le &lt;code>std::unique_ptr&lt;/code> du C++.&lt;/p>
&lt;div class="mermaid">sequenceDiagram
participant S1 as "Variable s1"
participant Heap as "Mémoire du tas ('hello')"
participant S2 as "Variable s2"
S1->>Heap: "Alloue et Possède"
Note over S1,S2: "let s2 = s1;"
S1--xHeap: "Perd la possession (Invalidé)"
S2->>Heap: "Prend la possession"&lt;/div>
&lt;h2 id="4-emprunt-borrowing-et-références">4. Emprunt (Borrowing) et Références
&lt;/h2>&lt;p>Déplacer la possession en permanence est très peu pratique, car il faudrait restituer la possession à chaque fois que l&amp;rsquo;on passe une valeur à une fonction. C&amp;rsquo;est là qu&amp;rsquo;intervient l&amp;rsquo;« Emprunt » (Borrowing). C&amp;rsquo;est l&amp;rsquo;équivalent des pointeurs et des références en C++.&lt;/p>
&lt;p>Il existe deux types d&amp;rsquo;emprunt en Rust :&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Référence immuable (Immutable Reference)&lt;/strong> : &lt;code>&amp;amp;T&lt;/code> (Proche de &lt;code>const T&amp;amp;&lt;/code> en C++)&lt;/li>
&lt;li>&lt;strong>Référence mutable (Mutable Reference)&lt;/strong> : &lt;code>&amp;amp;mut T&lt;/code> (Proche de &lt;code>T&amp;amp;&lt;/code> en C++)&lt;/li>
&lt;/ul>
&lt;h3 id="la-règle-impitoyable-du-borrow-checker">La règle impitoyable du Borrow Checker
&lt;/h3>&lt;p>Le compilateur de Rust intègre un « Borrow Checker » qui vérifie la validité des références. Le Borrow Checker impose la règle stricte suivante :&lt;/p>
&lt;blockquote>
&lt;p>Dans n&amp;rsquo;importe quelle portée, seule l&amp;rsquo;une des conditions suivantes peut exister à la fois :&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Une seule référence mutable (&lt;code>&amp;amp;mut T&lt;/code>)&lt;/strong>&lt;/li>
&lt;li>&lt;strong>Plusieurs références immuables (&lt;code>&amp;amp;T&lt;/code>)&lt;/strong>&lt;/li>
&lt;/ul>
&lt;/blockquote>
&lt;p>C&amp;rsquo;est ce qu&amp;rsquo;on appelle le principe &lt;strong>« Multiple Readers XOR Single Writer (MRSW) »&lt;/strong>. Cela peut s&amp;rsquo;exprimer par le OU exclusif logique (XOR) en mathématiques. Pour un état $S$, le nombre de références immuables $N_r$ et le nombre de références mutables $N_w$ doivent satisfaire la contrainte suivante :&lt;/p>
$$ (N_r \ge 0 \land N_w = 0) \oplus (N_r = 0 \land N_w = 1) $$
&lt;p>Grâce à cette règle, &lt;strong>les accès concurrents aux données (Data Race) sont complètement éliminés à la compilation&lt;/strong>. Une data race se produit lorsque : ① deux pointeurs ou plus accèdent à la même donnée simultanément, ② au moins un d&amp;rsquo;entre eux effectue une écriture, et ③ il n&amp;rsquo;y a pas de mécanisme de synchronisation. Rust détruit la condition ② à la compilation, prévenant ainsi les data races avant même qu&amp;rsquo;elles ne se produisent.&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;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-rust" data-lang="rust">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// Rust : Erreur de compilation due à une violation des règles d&amp;#39;emprunt
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="k">fn&lt;/span> &lt;span class="nf">main&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">let&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">mut&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">s&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="nb">String&lt;/span>::&lt;span class="n">from&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;hello&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">let&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">r1&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">&amp;amp;&lt;/span>&lt;span class="n">s&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c1">// Emprunt immuable (OK)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">let&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">r2&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">&amp;amp;&lt;/span>&lt;span class="n">s&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c1">// Emprunt immuable (OK)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c1">// let r3 = &amp;amp;mut s; // Erreur ! Impossible de créer un emprunt mutable alors que des emprunts immuables existent
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="fm">println!&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;&lt;/span>&lt;span class="si">{}&lt;/span>&lt;span class="s">, &lt;/span>&lt;span class="si">{}&lt;/span>&lt;span class="s">&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">r1&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">r2&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h2 id="5-prévention-de-linvalidation-ditérateur-iterator-invalidation">5. Prévention de l&amp;rsquo;invalidation d&amp;rsquo;itérateur (Iterator Invalidation)
&lt;/h2>&lt;p>Pour illustrer concrètement la puissance du Borrow Checker, examinons un bug classique appelé « invalidation d&amp;rsquo;itérateur ».&lt;/p>
&lt;h3 id="invalidation-ditérateur-en-c-plantage-à-lexécution">Invalidation d&amp;rsquo;itérateur en C++ (Plantage à l&amp;rsquo;exécution)
&lt;/h3>&lt;p>Si vous modifiez un &lt;code>std::vector&lt;/code> en C++ au sein d&amp;rsquo;une boucle, la mémoire sous-jacente peut être réallouée (Reallocation), transformant les références en pointeurs fantômes (dangling pointers).&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;/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">// C++ : Bug d&amp;#39;invalidation d&amp;#39;itérateur
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&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;vector&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="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">vector&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="kt">int&lt;/span>&lt;span class="o">&amp;gt;&lt;/span> &lt;span class="n">v&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">3&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">// Obtient une référence au premier élément du vecteur
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="kt">int&lt;/span>&lt;span class="o">&amp;amp;&lt;/span> &lt;span class="n">first&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">v&lt;/span>&lt;span class="p">[&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>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Ajoute un élément (si la capacité est insuffisante ici, un nouvel espace mémoire est alloué,
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="c1">// et l&amp;#39;ancien espace peut être détruit)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">v&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">push_back&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">4&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">// first peut maintenant pointer vers une mémoire déjà libérée ! (Comportement indéfini)
&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">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;Le premier élément est : &amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">first&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">endl&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="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;h3 id="défense-à-la-compilation-par-rust">Défense à la compilation par Rust
&lt;/h3>&lt;p>Écrivons exactement la même logique en Rust.&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;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-rust" data-lang="rust">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// Rust : Prévenir l&amp;#39;invalidation d&amp;#39;itérateur à la compilation
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="k">fn&lt;/span> &lt;span class="nf">main&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">let&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">mut&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">v&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="fm">vec!&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="mi">2&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="mi">3&lt;/span>&lt;span class="p">];&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">// Obtient une référence immuable (Début de l&amp;#39;emprunt)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">let&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">first&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">&amp;amp;&lt;/span>&lt;span class="n">v&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">];&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">// Erreur ! Tant que `first` emprunte `v` de manière immuable,
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c1">// l&amp;#39;emprunt mutable nécessaire pour `v.push` ne peut pas être effectué.
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c1">// v.push(4);
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="fm">println!&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;Le premier élément est : &lt;/span>&lt;span class="si">{}&lt;/span>&lt;span class="s">&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">first&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Ainsi, en Rust, « modifier une valeur (emprunt mutable) pendant qu&amp;rsquo;elle est en cours de lecture (emprunt immuable) » est interdit au niveau du compilateur. Par conséquent, les bugs fatals tels que Use-After-Free et l&amp;rsquo;invalidation d&amp;rsquo;itérateurs sont attrapés à coup sûr lors de la compilation.&lt;/p>
&lt;div class="mermaid">graph LR
A["Variable v (Propriétaire)"] --> B["Tableau sur le tas [1, 2, 3]"]
C["Référence 'first' (&amp;v[0])"] -.->|"Emprunt immuable"| B
A -->|X "Emprunt mutable refusé !"| D["v.push(4)"]
style C stroke:#00FF00,stroke-width:2px
style D stroke:#FF0000,stroke-width:2px&lt;/div>
&lt;h2 id="6-possession-partagée-dans-rust--rc-et-arc">6. Possession partagée dans Rust : &lt;code>Rc&lt;/code> et &lt;code>Arc&lt;/code>
&lt;/h2>&lt;p>Rust propose également des modèles de possession partagée équivalents au &lt;code>std::shared_ptr&lt;/code> de C++, mais les types sont clairement séparés pour une utilisation sur un seul thread (monothread) ou sur plusieurs threads (multithread).&lt;/p>
&lt;h3 id="pour-monothread--rct-reference-counted">Pour monothread : &lt;code>Rc&amp;lt;T&amp;gt;&lt;/code> (Reference Counted)
&lt;/h3>&lt;p>&lt;code>Rc&amp;lt;T&amp;gt;&lt;/code> est un pointeur intelligent à compteur de références qui n&amp;rsquo;est pas thread-safe. Comme il incrémente et décrémente le compteur sans utiliser d&amp;rsquo;instructions atomiques, il est extrêmement rapide au sein d&amp;rsquo;un seul thread. Cependant, si vous essayez de l&amp;rsquo;envoyer vers un autre thread, vous obtiendrez une erreur de compilation (car il n&amp;rsquo;implémente pas le trait &lt;code>Send&lt;/code>).&lt;/p>
&lt;h3 id="pour-multithread--arct-atomic-reference-counted">Pour multithread : &lt;code>Arc&amp;lt;T&amp;gt;&lt;/code> (Atomic Reference Counted)
&lt;/h3>&lt;p>Lors du partage entre plusieurs threads, on utilise &lt;code>Arc&amp;lt;T&amp;gt;&lt;/code>, qui effectue des incrémentations et décrémentations atomiques. Son coût est équivalent à celui de &lt;code>std::shared_ptr&lt;/code> en C++.&lt;/p>
&lt;p>De plus, en C++, si vous écrivez simultanément à partir de plusieurs threads dans une variable partagée par &lt;code>std::shared_ptr&lt;/code>, une Data Race se produit. Pour éviter cela, vous devez utiliser correctement et manuellement un &lt;code>std::mutex&lt;/code>.&lt;/p>
&lt;p>En revanche, en Rust, &lt;strong>il est impossible de modifier les données internes&lt;/strong> d&amp;rsquo;un &lt;code>Arc&amp;lt;T&amp;gt;&lt;/code> seul. Si des modifications sont nécessaires, il faut le combiner avec un mutex, &lt;code>Mutex&amp;lt;T&amp;gt;&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;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-rust" data-lang="rust">&lt;span class="line">&lt;span class="cl">&lt;span class="k">use&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">std&lt;/span>::&lt;span class="n">sync&lt;/span>::&lt;span class="p">{&lt;/span>&lt;span class="n">Arc&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">Mutex&lt;/span>&lt;span class="p">};&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="k">use&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">std&lt;/span>::&lt;span class="n">thread&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="k">fn&lt;/span> &lt;span class="nf">main&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">// Combinaison d&amp;#39;un partage thread-safe et d&amp;#39;une exclusion mutuelle
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c1">// Semblable à std::shared_ptr&amp;lt;std::mutex&amp;gt; en C++, mais Mutex englobe les données
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">let&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">counter&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">Arc&lt;/span>::&lt;span class="n">new&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">Mutex&lt;/span>::&lt;span class="n">new&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">));&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">let&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">mut&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">handles&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="fm">vec!&lt;/span>&lt;span class="p">[];&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">for&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">_&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">in&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="o">..&lt;/span>&lt;span class="mi">10&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">let&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">counter_clone&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">Arc&lt;/span>::&lt;span class="n">clone&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">&amp;amp;&lt;/span>&lt;span class="n">counter&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="kd">let&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">handle&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">thread&lt;/span>::&lt;span class="n">spawn&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="k">move&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">||&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">// Ce n&amp;#39;est qu&amp;#39;en appelant lock() que l&amp;#39;on obtient une référence mutable (&amp;amp;mut i32) sur l&amp;#39;intérieur
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kd">let&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">mut&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">num&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">counter_clone&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">lock&lt;/span>&lt;span class="p">().&lt;/span>&lt;span class="n">unwrap&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="o">*&lt;/span>&lt;span class="n">num&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">+=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">});&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="c1">// Le verrou est automatiquement libéré à la sortie de la portée grâce à RAII
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">handles&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">push&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">handle&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">for&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">handle&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">in&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">handles&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">handle&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">join&lt;/span>&lt;span class="p">().&lt;/span>&lt;span class="n">unwrap&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="fm">println!&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;Résultat : &lt;/span>&lt;span class="si">{}&lt;/span>&lt;span class="s">&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">*&lt;/span>&lt;span class="n">counter&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">lock&lt;/span>&lt;span class="p">().&lt;/span>&lt;span class="n">unwrap&lt;/span>&lt;span class="p">());&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Ce qui est remarquable, c&amp;rsquo;est que le &lt;code>Mutex&amp;lt;T&amp;gt;&lt;/code> de Rust n&amp;rsquo;est pas qu&amp;rsquo;un simple mécanisme de verrouillage, il &lt;strong>« englobe les données à protéger en tant que type »&lt;/strong>. Cela permet d&amp;rsquo;empêcher totalement au niveau de la compilation l&amp;rsquo;erreur classique d&amp;rsquo;« oublier de prendre le verrou avant d&amp;rsquo;accéder aux données ». À moins d&amp;rsquo;obtenir le verrou (&lt;code>lock()&lt;/code>), il est structurellement impossible d&amp;rsquo;obtenir un droit d&amp;rsquo;accès (une référence) au contenu des données.&lt;/p>
&lt;h2 id="conclusion---inspection-préalable--par-le-compilateur-ou--responsabilité-personnelle--des-développeurs">Conclusion : « Inspection préalable » par le compilateur ou « Responsabilité personnelle » des développeurs
&lt;/h2>&lt;p>Les pointeurs C++ et les pointeurs intelligents offrent aux développeurs un contrôle avancé et d&amp;rsquo;excellentes performances, mais leur utilisation correcte dépend de la discipline du développeur. L&amp;rsquo;introduction de RAII et de &lt;code>std::unique_ptr&lt;/code> a rendu C++ considérablement plus sûr, mais il est toujours impossible de prévenir totalement au niveau du langage des « comportements indéfinis » tels que l&amp;rsquo;accès après un déplacement (move) ou l&amp;rsquo;invalidation d&amp;rsquo;itérateur.&lt;/p>
&lt;p>D&amp;rsquo;un autre côté, Rust intègre les règles de possession (Ownership) et d&amp;rsquo;emprunt (Borrowing) au compilateur, ce qui permet de détecter ces erreurs au moment de la &lt;strong>compilation&lt;/strong> plutôt qu&amp;rsquo;à l&amp;rsquo;exécution. La garantie forte qui dit que « si cela compile, c&amp;rsquo;est que la mémoire est sûre » est la principale raison pour laquelle Rust gagne rapidement le soutien du monde de la programmation système.&lt;/p>
&lt;p>Le fait de lutter contre le Borrow Checker de Rust (Fight the borrow checker) représente un mur important pour les débutants, mais ce n&amp;rsquo;est rien de plus que le compilateur effectuant strictement à votre place le calcul complexe du « suivi de la durée de vie des pointeurs » que les programmeurs C++ faisaient traditionnellement dans leur tête.&lt;/p>
&lt;p>Si vous apprenez Rust après avoir compris la liberté et les dangers des pointeurs C++, vous pourrez comprendre bien plus en profondeur la philosophie qui se cache derrière la conception du modèle de possession, à savoir « pourquoi cela a-t-il été conçu ainsi ? ».&lt;/p>
&lt;hr>
&lt;p>&lt;em>Cet article est une comparaison et une réflexion sur les méthodes de gestion de la mémoire en C++ et Rust. Nous espérons qu&amp;rsquo;il vous sera utile pour choisir le langage approprié en fonction des exigences de votre projet.&lt;/em>&lt;/p></description></item></channel></rss>