<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Rust on kenji.blog</title><link>http://kenji.blog/fr/categories/rust/</link><description>Recent content in Rust 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/categories/rust/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><item><title>Avantages et inconvénients de Rust vus par un ingénieur C++</title><link>http://kenji.blog/fr/p/cpp-engineer-learning-rust-pros-cons/</link><pubDate>Sat, 12 Sep 2026 03:00:00 +0900</pubDate><guid>http://kenji.blog/fr/p/cpp-engineer-learning-rust-pros-cons/</guid><description>&lt;img src="http://kenji.blog/p/cpp-engineer-learning-rust-pros-cons/img/eyecatch.jpg" alt="Featured image of post Avantages et inconvénients de Rust vus par un ingénieur C++" />&lt;h1 id="introduction--une-nouvelle-aube-pour-la-programmation-système">Introduction : Une nouvelle aube pour la programmation système
&lt;/h1>&lt;p>Dans l&amp;rsquo;ingénierie logicielle moderne, C++ et Rust sont les deux géants à l&amp;rsquo;avant-garde de la programmation système. Pendant de nombreuses années, le C++ a régné en maître absolu dans les domaines poussant les performances matérielles à leurs limites extrêmes, tels que les systèmes d&amp;rsquo;exploitation, les appareils embarqués, les moteurs de jeu et les systèmes de trading à haute fréquence (HFT). En tant qu&amp;rsquo;ingénieur C++ senior moi-même, j&amp;rsquo;ai commencé dans la jungle des pointeurs bruts de l&amp;rsquo;ère C++98, et j&amp;rsquo;ai continué à écrire du code tout en suivant la vague de modernisation apportée par C++11 (pointeurs intelligents, expressions lambda et l&amp;rsquo;introduction de &lt;code>auto&lt;/code>), ainsi que l&amp;rsquo;expansion massive des spécifications qui a suivi avec C++14/17/20.&lt;/p>
&lt;p>Cependant, ces dernières années, Rust a connu une montée en puissance spectaculaire en tant que solution aux problèmes structurels du C++, en particulier le &amp;ldquo;manque de sécurité de la mémoire&amp;rdquo; entraînant des vulnérabilités de sécurité (on dit qu&amp;rsquo;environ 70 % des CVE sont liés à la mémoire) et les &amp;ldquo;spécifications infiniment complexes et comportements indéfinis (UB)&amp;rdquo;. Son adoption officielle dans le noyau Linux et les projets de migration à grande échelle vers Rust par des géants de la technologie comme Microsoft, Google et AWS ne sont pas qu&amp;rsquo;une simple tendance passagère, mais signifient un véritable changement de paradigme dans la programmation système.&lt;/p>
&lt;p>Dans cet article, je vais comparer et expliquer en détail les &amp;ldquo;avantages&amp;rdquo; et les &amp;ldquo;inconvénients&amp;rdquo; que j&amp;rsquo;ai ressentis en tant que pur ingénieur C++ ayant appris Rust en profondeur et l&amp;rsquo;ayant utilisé en pratique, d&amp;rsquo;un point de vue technique lié aux fondements même du langage.&lt;/p>
&lt;hr>
&lt;h1 id="1-changement-de-paradigme-de-la-gestion-de-la-mémoire--du-raii-à-la-possession-ownership-et-lemprunt-borrowing">1. Changement de paradigme de la gestion de la mémoire : Du RAII à la possession (Ownership) et l&amp;rsquo;emprunt (Borrowing)
&lt;/h1>&lt;h2 id="le-raii-en-c-et-les-limites-des-pointeurs-intelligents">Le RAII en C++ et les limites des pointeurs intelligents
&lt;/h2>&lt;p>L&amp;rsquo;une des plus grandes inventions du C++ est le &lt;strong>RAII (Resource Acquisition Is Initialization)&lt;/strong>. Ce concept, qui consiste à allouer des ressources dans le constructeur et à les libérer automatiquement dans le destructeur lorsqu&amp;rsquo;elles sortent de la portée, a libéré les développeurs de la peur des fuites de mémoire dues aux &lt;code>new&lt;/code> et &lt;code>delete&lt;/code> manuels. Depuis C++11, &lt;code>std::unique_ptr&lt;/code> et &lt;code>std::shared_ptr&lt;/code> ont été introduits dans la bibliothèque standard, permettant d&amp;rsquo;exprimer le concept de possession (Ownership) dans le code.&lt;/p>
&lt;p>Cependant, les pointeurs intelligents du C++ et la sémantique de déplacement (move semantics) ont une faiblesse fatale : la vérification statique par le compilateur est incomplète.&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-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">#include&lt;/span> &lt;span class="cpf">&amp;lt;string&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">consume&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">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">string&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">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;Consuming: &amp;#34;&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>&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">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">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">string&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;Hello, C++&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="c1">// Déplace la possession (Ownership) vers la fonction (Move)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">consume&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>&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">// Danger : En C++, l&amp;#39;accès à un objet après son déplacement ne provoque pas d&amp;#39;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="c1">// std::move n&amp;#39;est qu&amp;#39;un cast vers une référence de rvalue (T&amp;amp;&amp;amp;), et le compilateur ne bloque pas son utilisation
&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">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;Pointer is still valid?&amp;#34;&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 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;Pointer is null.&amp;#34;&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 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">// std::cout &amp;lt;&amp;lt; *my_ptr &amp;lt;&amp;lt; std::endl; // Comportement indéfini (UB) causé par l&amp;#39;utilisation de mémoire après libération (Use-After-Free)
&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>En C++, il y a toujours un risque d&amp;rsquo;accéder accidentellement à un objet qui a été vidé par &lt;code>std::move&lt;/code> (un état valide mais non spécifié). Cela conduit directement à des plantages à l&amp;rsquo;exécution ou, dans le pire des cas, à des failles de sécurité.&lt;/p>
&lt;h2 id="la-possession-ownership-en-rust-et-la-défense-absolue-du-borrow-checker">La possession (Ownership) en Rust et la défense absolue du Borrow Checker
&lt;/h2>&lt;p>Rust intègre ce concept de &amp;ldquo;possession&amp;rdquo; dans la conception même du langage et effectue une analyse statique stricte grâce à une fonctionnalité du compilateur appelée &lt;strong>Borrow Checker&lt;/strong> (vérificateur d&amp;rsquo;emprunt).&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="k">fn&lt;/span> &lt;span class="nf">consume&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">s&lt;/span>: &lt;span class="nb">String&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="fm">println!&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;Consuming: &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">s&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">// Ici, s sort de la portée et la mémoire est libérée (Drop)
&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="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">my_string&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, Rust&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="c1">// Déplace la possession vers la fonction. En Rust, la sémantique de déplacement est la valeur par défaut.
&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">consume&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">my_string&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 de compilation ! Il est absolument impossible d&amp;#39;accéder à une variable après son déplacement
&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;Is it still there? {}&amp;#34;, my_string);
&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>En Rust, lorsque la possession d&amp;rsquo;une variable est transférée, la variable d&amp;rsquo;origine est traitée par le compilateur comme étant équivalente à un état &amp;ldquo;non initialisé&amp;rdquo;, bloquant complètement tout accès ultérieur. Par conséquent, les bugs tels que l&amp;rsquo;&amp;ldquo;utilisation après libération (Use-After-Free)&amp;rdquo; ou les &amp;ldquo;pointeurs fantômes (Dangling Pointers)&amp;rdquo; ne peuvent théoriquement pas passer la compilation.&lt;/p>
&lt;div class="mermaid">graph TD
A["C++ std::unique_ptr"] --> B["std::move appliqué"]
B --> C["Possession transférée"]
C --> D["L'ancien pointeur est toujours accessible"]
D --> E["Comportement indéfini (UB) potentiel"]
F["Rust Box / String"] --> G["Passé par valeur (Déplacement)"]
G --> H["Possession transférée"]
H --> I["Le compilateur bloque l'ancienne variable"]
I --> J["Sécurité de la mémoire garantie"]&lt;/div>
&lt;h2 id="emprunt-borrowing-et-contrôle-de-la-mutabilité">Emprunt (Borrowing) et contrôle de la mutabilité
&lt;/h2>&lt;p>Ce qui est encore plus puissant, ce sont les règles d&amp;rsquo;&amp;ldquo;emprunt (Borrowing)&amp;rdquo; qui font référence aux ressources. En Rust, les règles suivantes sont imposées :&lt;/p>
&lt;ol>
&lt;li>À tout moment, il ne peut y avoir &lt;strong>soit&lt;/strong> que &amp;ldquo;plusieurs références immuables (&lt;code>&amp;amp;T&lt;/code>)&amp;rdquo;, &lt;strong>soit&lt;/strong> qu&amp;rsquo;&amp;ldquo;une seule référence mutable (&lt;code>&amp;amp;mut T&lt;/code>)&amp;rdquo;.&lt;/li>
&lt;li>Les références ne doivent pas vivre plus longtemps que la portée des données d&amp;rsquo;origine (contraintes de durée de vie).&lt;/li>
&lt;/ol>
&lt;p>En C++, il est facile de créer plusieurs références mutables ou pointeurs vers le même objet, ce qui peut causer des destructions d&amp;rsquo;état inattendues (comme l&amp;rsquo;invalidation d&amp;rsquo;itérateurs). Rust empêche ces bugs en interdisant la combinaison de &amp;ldquo;l&amp;rsquo;aliasing + la mutabilité&amp;rdquo; au niveau du langage.&lt;/p>
&lt;hr>
&lt;h1 id="2-agencement-de-la-mémoire-et-coût-mathématique-des-pointeurs-intelligents">2. Agencement de la mémoire et coût mathématique des pointeurs intelligents
&lt;/h1>&lt;p>Dans la programmation système, une compréhension précise de l&amp;rsquo;agencement de la mémoire est essentielle. Comparons le &lt;code>std::shared_ptr&lt;/code> du C++ avec le &lt;code>std::rc::Rc&lt;/code> / &lt;code>std::sync::Arc&lt;/code> de Rust.&lt;/p>
&lt;p>Le &lt;code>std::shared_ptr&lt;/code> en C++ gère les ressources par comptage de références, mais par défaut, il utilise des opérations atomiques thread-safe (&lt;code>std::atomic&lt;/code>) pour incrémenter ou décrémenter le compteur de références. Son coût (overhead) en mémoire peut être formulé comme suit :&lt;/p>
$$ Overhead_{C++} = sizeof(T) + sizeof(ControlBlock) $$
&lt;p>Ici, $ControlBlock$ comprend le &amp;ldquo;compteur de références fortes (Strong Ref Count)&amp;rdquo;, le &amp;ldquo;compteur de références faibles (Weak Ref Count)&amp;rdquo; et un &amp;ldquo;suppresseur personnalisé (Custom Deleter)&amp;rdquo;. Le problème est que, même si l&amp;rsquo;objet n&amp;rsquo;est utilisé que dans un seul thread, le coût des instructions atomiques (comme le verrouillage de la ligne de cache, etc.) se produit de manière inconditionnelle.&lt;/p>
&lt;p>En revanche, Rust sépare strictement les pointeurs intelligents en fonction de leur utilisation.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Pour le single-thread&lt;/strong> : &lt;code>Rc&amp;lt;T&amp;gt;&lt;/code> (Reference Counted)&lt;/li>
&lt;li>&lt;strong>Pour le multi-thread&lt;/strong> : &lt;code>Arc&amp;lt;T&amp;gt;&lt;/code> (Atomic Reference Counted)&lt;/li>
&lt;/ul>
$$ Overhead_{Rc} = sizeof(T) + 2 \times sizeof(usize) $$
$$ Overhead_{Arc} = sizeof(T) + 2 \times sizeof(AtomicUsize) $$
&lt;p>En Rust, si vous utilisez &lt;code>Rc&amp;lt;T&amp;gt;&lt;/code>, qui est dédié à un usage single-thread, vous pouvez éviter complètement la pénalité des opérations atomiques (abstraction à coût zéro). Et, grâce au mécanisme de thread-safety décrit ci-dessous, le système de types empêche complètement de passer par erreur un &lt;code>Rc&amp;lt;T&amp;gt;&lt;/code> à un autre thread.&lt;/p>
&lt;hr>
&lt;h1 id="3-thread-safety--le-choc-de-la-fearless-concurrency-concurrence-sans-peur">3. Thread-Safety : Le choc de la &amp;ldquo;Fearless Concurrency&amp;rdquo; (Concurrence sans peur)
&lt;/h1>&lt;p>La programmation multi-thread en C++ a toujours été accompagnée de la peur des data races (conditions de course de données) et des deadlocks (interblocages).&lt;/p>
&lt;h2 id="les-dangers-des-mutex-c-et-de-la-séparation-des-données">Les dangers des mutex C++ et de la séparation des données
&lt;/h2>&lt;p>Le &lt;code>std::mutex&lt;/code> en C++ ne fournit un contrôle exclusif que sur &amp;ldquo;un bloc de code spécifique (section critique)&amp;rdquo;, et il n&amp;rsquo;y a aucun lien au niveau du langage entre &amp;ldquo;les données à protéger&amp;rdquo; et &amp;ldquo;le mutex&amp;rdquo;.&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;/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;thread&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;mutex&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="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">shared_data&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">mutex&lt;/span> &lt;span class="n">mtx&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">void&lt;/span> &lt;span class="nf">worker&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="c1">// Même si le développeur oublie d&amp;#39;acquérir le verrou, la compilation réussira normalement
&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::lock_guard&amp;lt;std::mutex&amp;gt; lock(mtx);
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">shared_data&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">1&lt;/span>&lt;span class="p">);&lt;/span> &lt;span class="c1">// Data race fatale !
&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="kr">thread&lt;/span> &lt;span class="n">t1&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">worker&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="kr">thread&lt;/span> &lt;span class="n">t2&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">worker&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">t1&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">join&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">t2&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">join&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="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;h2 id="le-mutex-en-rust-possède-les-données">Le Mutex en Rust &amp;ldquo;possède&amp;rdquo; les données
&lt;/h2>&lt;p>En Rust, &lt;code>Mutex&amp;lt;T&amp;gt;&lt;/code> utilise des génériques pour &lt;strong>encapsuler (posséder)&lt;/strong> le type de données &lt;code>T&lt;/code> à protéger. Pour accéder aux données, il est obligatoire d&amp;rsquo;appeler &lt;code>lock()&lt;/code> pour obtenir un objet de garde (guard). Toucher aux données sans acquérir le verrou est syntaxiquement impossible.&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-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">// Les données sont complètement encapsulées dans le Mutex
&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">shared_data&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="nb">Vec&lt;/span>::&lt;span class="n">new&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">2&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">// Clone de l&amp;#39;Arc (comptage de références thread-safe) pour partager entre les threads
&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">data_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">shared_data&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">// Impossible d&amp;#39;accéder au Vec interne sans obtenir le verrou
&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">data&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">data_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="n">data&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">push&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>&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 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 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>De plus, Rust possède deux traits de base (core traits) qui garantissent la sécurité de la concurrence :&lt;/p>
&lt;ul>
&lt;li>&lt;code>Send&lt;/code> : Type dont la possession peut être transférée en toute sécurité entre les threads&lt;/li>
&lt;li>&lt;code>Sync&lt;/code> : Type qui peut être référencé simultanément par plusieurs threads en toute sécurité&lt;/li>
&lt;/ul>
&lt;p>Par exemple, &lt;code>Rc&amp;lt;T&amp;gt;&lt;/code>, qui n&amp;rsquo;est pas thread-safe, n&amp;rsquo;implémente pas le trait &lt;code>Send&lt;/code>. Par conséquent, si vous essayez de le passer à &lt;code>thread::spawn&lt;/code>, cela entraînera une erreur de compilation immédiate. Grâce à cette &amp;ldquo;Fearless Concurrency&amp;rdquo; (Concurrence sans peur), les développeurs sont libérés de la peur des bugs et peuvent pousser la parallélisation de manière beaucoup plus agressive.&lt;/p>
&lt;p>Selon la loi d&amp;rsquo;Amdahl (Amdahl&amp;rsquo;s Law), le débit maximal théorique avec une partie parallélisable $P$ et un degré de parallélisme $N$ est exprimé comme suit :&lt;/p>
$$ S(N) = \frac{1}{(1 - P) + \frac{P}{N}} $$
&lt;p>Rust permet d&amp;rsquo;effectuer des refactorisations pour maximiser ce $P$ en toute sécurité en s&amp;rsquo;appuyant sur le système de types.&lt;/p>
&lt;div class="mermaid">graph TD
A["Thread Safety en C++"] --> B["Repose sur la mémoire du développeur"]
B --> C["Mutex dissocié des données"]
C --> D["Risque élevé de data races silencieuses"]
E["Thread Safety en Rust"] --> F["Traits Send et Sync"]
F --> G["Le Mutex possède les données"]
G --> H["Data races évitées à la compilation"]&lt;/div>
&lt;hr>
&lt;h1 id="4-gestion-des-erreurs--exceptions-vs-types-de-données-algébriques">4. Gestion des erreurs : Exceptions vs Types de données algébriques
&lt;/h1>&lt;p>Le standard pour la gestion des erreurs en C++ est l&amp;rsquo;utilisation des &amp;ldquo;exceptions&amp;rdquo;. Cependant, les exceptions rendent le flux de contrôle opaque et entraînent des pénalités de performances (déroulement de la pile ou stack unwinding, et augmentation du RTTI). Dans les systèmes embarqués ou les moteurs de jeu, il est courant de désactiver complètement les exceptions (&lt;code>-fno-exceptions&lt;/code>) et d&amp;rsquo;adopter une conception renvoyant des codes d&amp;rsquo;erreur classiques. Bien que &lt;code>std::expected&lt;/code> ait été introduit dans C++23, il faudra du temps pour qu&amp;rsquo;il pénètre l&amp;rsquo;ensemble de l&amp;rsquo;écosystème.&lt;/p>
&lt;p>Le concept d&amp;rsquo;exception n&amp;rsquo;existe pas en Rust. Les erreurs sont renvoyées comme des &amp;ldquo;valeurs&amp;rdquo; pures et sont exprimées par l&amp;rsquo;énumération (type de données algébrique) &lt;code>Result&amp;lt;T, E&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;/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">fs&lt;/span>::&lt;span class="n">File&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">io&lt;/span>::&lt;span class="p">{&lt;/span>&lt;span class="bp">self&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">Read&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">// Rien qu&amp;#39;en regardant le type de retour, il est clair qu&amp;#39;une erreur d&amp;#39;E/S peut se produire
&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">read_file_content&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">path&lt;/span>: &lt;span class="kp">&amp;amp;&lt;/span>&lt;span class="kt">str&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="w"> &lt;/span>-&amp;gt; &lt;span class="nb">Result&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="nb">String&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">io&lt;/span>::&lt;span class="n">Error&lt;/span>&lt;span class="o">&amp;gt;&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">// L&amp;#39;opérateur ? effectue un retour anticipé immédiat s&amp;#39;il y a une erreur, ou extrait le contenu en cas de succès
&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">file&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">File&lt;/span>::&lt;span class="n">open&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">path&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">?&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">content&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">new&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">file&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">read_to_string&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">&amp;amp;&lt;/span>&lt;span class="k">mut&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">content&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">?&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="nb">Ok&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">content&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>Cet opérateur &lt;code>?&lt;/code> est révolutionnaire. Il élimine l&amp;rsquo;imbrication profonde (la pyramide de if) qui se produit lors de la vérification des codes d&amp;rsquo;erreur en C++, maintient un flux de code propre similaire à celui des exceptions, tout en décrivant explicitement à quels appels de fonction les erreurs sont propagées.&lt;/p>
&lt;hr>
&lt;h1 id="5-polymorphisme--des-fonctions-virtuelles-et-templates-aux-traits">5. Polymorphisme : Des fonctions virtuelles et templates aux Traits
&lt;/h1>&lt;p>Le polymorphisme en C++ est principalement réalisé par la répartition dynamique (dynamic dispatch) via l&amp;rsquo;héritage de classes et les fonctions virtuelles (&lt;code>virtual&lt;/code>), ou par la répartition statique (static dispatch) via les templates (comme CRTP).&lt;/p>
&lt;p>Dans la répartition dynamique, un pointeur vers la table des fonctions virtuelles (vptr vers vtable) est intégré dans l&amp;rsquo;objet, ce qui entraîne un coût de résolution du pointeur lors de l&amp;rsquo;appel de la fonction.&lt;/p>
$$ T_{dispatch} = T_{lookup\_in\_vtable} + T_{dereference} $$
&lt;p>Rust a abandonné l&amp;rsquo;&amp;ldquo;héritage de classes&amp;rdquo; classique orienté objet et a adopté à la place le concept de &amp;ldquo;&lt;strong>Traits&lt;/strong>&amp;rdquo; (similaire aux Concepts de C++20, mais avec plus de fonctionnalités).&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;/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">trait&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">Drawable&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="k">fn&lt;/span> &lt;span class="nf">draw&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">&amp;amp;&lt;/span>&lt;span class="bp">self&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">struct&lt;/span> &lt;span class="nc">Circle&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">radius&lt;/span>: &lt;span class="kt">f64&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">impl&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">Drawable&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">for&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">Circle&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="k">fn&lt;/span> &lt;span class="nf">draw&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">&amp;amp;&lt;/span>&lt;span class="bp">self&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 class="fm">println!&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;Drawing a Circle of radius &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="bp">self&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">radius&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="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">// Répartition statique (monomorphisation, sans coût supplémentaire / zero-overhead)
&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">draw_static&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">T&lt;/span>: &lt;span class="nc">Drawable&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">item&lt;/span>: &lt;span class="kp">&amp;amp;&lt;/span>&lt;span class="nc">T&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="n">item&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">draw&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="c1">// Répartition dynamique (objets de trait)
&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">draw_dynamic&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">item&lt;/span>: &lt;span class="kp">&amp;amp;&lt;/span>&lt;span class="nc">dyn&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">Drawable&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="n">item&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">draw&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>La principale caractéristique de la répartition dynamique de Rust (&lt;code>dyn Trait&lt;/code>) est qu&amp;rsquo;elle n&amp;rsquo;a pas de vptr dans la structure de données, mais utilise un &lt;strong>Fat Pointer&lt;/strong> (pointeur lourd). Un Fat Pointer contient une paire : &amp;ldquo;un pointeur vers les données&amp;rdquo; et &amp;ldquo;un pointeur vers la vtable&amp;rdquo;. Il est ainsi très facile d&amp;rsquo;implémenter (étendre) un trait pour un type défini dans une bibliothèque externe a posteriori et de le soumettre à une répartition dynamique.&lt;/p>
&lt;hr>
&lt;h1 id="6-gestion-des-paquets-et-système-de-build--lagonie-de-cmake-et-les-bienfaits-de-cargo">6. Gestion des paquets et système de build : L&amp;rsquo;agonie de CMake et les bienfaits de Cargo
&lt;/h1>&lt;p>L&amp;rsquo;une des plus grandes faiblesses du C++ est l&amp;rsquo;absence d&amp;rsquo;un gestionnaire de paquets standard. La syntaxe obscure de &lt;code>CMakeLists.txt&lt;/code>, la complexité de la résolution des dépendances avec &lt;code>find_package&lt;/code> et les différences dans les chemins de bibliothèques entre les systèmes d&amp;rsquo;exploitation ont continuellement fait perdre un temps énorme aux ingénieurs C++.&lt;/p>
&lt;p>Rust est livré en standard avec &lt;strong>Cargo&lt;/strong>, l&amp;rsquo;un des meilleurs gestionnaires de paquets et systèmes de build au monde.&lt;/p>
&lt;div class="mermaid">graph TD
A["Environnement de build C++"] --> B["CMakeLists.txt"]
B --> C["Intégration de vcpkg / Conan"]
C --> D["Génération de Makefiles / Ninja"]
D --> E["Compilateur (GCC/Clang/MSVC)"]
F["Environnement de build Rust"] --> G["Cargo.toml"]
G --> H["Récupération des dépendances depuis crates.io"]
H --> I["rustc (Cargo build)"]
I --> J["Binaire prêt à l'emploi"]&lt;/div>
&lt;p>Il suffit d&amp;rsquo;ajouter une ligne avec le nom et la version de la bibliothèque dépendante (crate) dans &lt;code>Cargo.toml&lt;/code>, et il gérera la résolution des dépendances transitives, le téléchargement et la compilation de manière entièrement automatique. De plus, tous les outils nécessaires au développement, tels que les tests (&lt;code>cargo test&lt;/code>), la génération de la documentation (&lt;code>cargo doc&lt;/code>), l&amp;rsquo;analyse statique (&lt;code>cargo clippy&lt;/code>) et le formateur (&lt;code>cargo fmt&lt;/code>), sont intégrés dans cette seule commande. Ce confort est tel qu&amp;rsquo;une fois que vous y avez goûté, son pouvoir destructeur vous empêche de vouloir revenir à l&amp;rsquo;environnement de build du C++.&lt;/p>
&lt;hr>
&lt;h1 id="7-les-inconvénients-et-la-courbe-dapprentissage-de-rust">7. Les inconvénients et la courbe d&amp;rsquo;apprentissage de Rust
&lt;/h1>&lt;p>Bien que j&amp;rsquo;aie vanté les mérites de Rust jusqu&amp;rsquo;ici, il y a certainement des &amp;ldquo;murs&amp;rdquo; et des inconvénients auxquels un ingénieur C++ devra faire face lors du déploiement de Rust en production.&lt;/p>
&lt;h2 id="1-la-lutte-acharnée-avec-le-borrow-checker">1. La lutte acharnée avec le Borrow Checker
&lt;/h2>&lt;p>Si vous essayez d&amp;rsquo;implémenter des structures de données que vous auriez &amp;ldquo;vaguement connectées avec des pointeurs bruts&amp;rdquo; en C++ (comme les listes doublement chaînées, les graphes ou les structures auto-référentielles) directement en Rust, la compilation échouera en raison des contraintes de possession (ownership) et de durée de vie (lifetimes). Pour satisfaire le Borrow Checker, vous devez soit utiliser des enveloppes (wrappers) complexes comme &lt;code>Rc&amp;lt;RefCell&amp;lt;T&amp;gt;&amp;gt;&lt;/code>, soit revoir fondamentalement la conception avec un allocateur d&amp;rsquo;arène ou une gestion basée sur des index.&lt;/p>
&lt;h2 id="2-la-longueur-des-temps-de-compilation">2. La longueur des temps de compilation
&lt;/h2>&lt;p>Tout comme le C++ ralentit la compilation avec l&amp;rsquo;imbrication des templates, le temps de compilation de Rust (en particulier pour les builds propres à partir de zéro) n&amp;rsquo;est en aucun cas court. Les puissantes passes d&amp;rsquo;optimisation de LLVM, l&amp;rsquo;expansion des macros et la monomorphisation des génériques s&amp;rsquo;accumulent, ce qui fait du temps de compilation un goulot d&amp;rsquo;étranglement dans les grands projets. Pendant le développement, des astuces comme l&amp;rsquo;utilisation intensive de &lt;code>cargo check&lt;/code> sont indispensables.&lt;/p>
&lt;h2 id="3-linteropérabilité-avec-les-bases-de-code-c">3. L&amp;rsquo;interopérabilité avec les bases de code C++
&lt;/h2>&lt;p>Bien que l&amp;rsquo;intégration avec le langage C (FFI) soit très fluide, il est extrêmement difficile d&amp;rsquo;intégrer directement Rust avec d&amp;rsquo;énormes bases de code C++ existantes (celles qui utilisent massivement des classes, des templates et des fonctions virtuelles). Ces dernières années, des outils de liaison (bridge tools) comme &lt;code>cxx&lt;/code> et &lt;code>autocxx&lt;/code> ont évolué, mais il y a encore de grands obstacles à surmonter pour une transition complètement fluide.&lt;/p>
&lt;hr>
&lt;h1 id="conclusion--devons-nous-passer-à-rust-">Conclusion : Devons-nous passer à Rust ?
&lt;/h1>&lt;p>Le C++ continuera de jouer un rôle important dans le développement de moteurs de jeu et dans les énormes infrastructures existantes. Sa modernisation avec C++20/23 est également remarquable, permettant d&amp;rsquo;écrire du code de manière plus sûre.&lt;/p>
&lt;p>Cependant, pour les &amp;ldquo;nouveaux projets de programmation système&amp;rdquo;, je trouve qu&amp;rsquo;il est désormais &lt;strong>plus difficile de trouver des raisons de ne pas choisir Rust&lt;/strong>. La &amp;ldquo;certitude&amp;rdquo; de Rust—une fois que ça compile, vous êtes libéré de la peur des comportements indéfinis et de la corruption de mémoire, et vous pouvez gérer la concurrence en toute sécurité avec de hautes performances—améliore radicalement le modèle mental de l&amp;rsquo;ingénieur.&lt;/p>
&lt;p>Pour un ingénieur C++, apprendre Rust ne se limite pas à mémoriser une nouvelle syntaxe ; c&amp;rsquo;est une excellente expérience qui offre une nouvelle perspective sur &amp;ldquo;la gestion sûre de la mémoire et des threads&amp;rdquo;. Je vous encourage vivement à expérimenter par vous-même le confort de Cargo et la rigueur du Borrow Checker.&lt;/p></description></item></channel></rss>