<?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/es/categories/rust/</link><description>Recent content in Rust on kenji.blog</description><generator>Hugo -- gohugo.io</generator><language>es</language><copyright>kenjinote</copyright><lastBuildDate>Sat, 12 Sep 2026 04:00:00 +0900</lastBuildDate><atom:link href="http://kenji.blog/es/categories/rust/index.xml" rel="self" type="application/rss+xml"/><item><title>Comparando la "Propiedad" y el "Préstamo" de Rust con los Punteros de C++</title><link>http://kenji.blog/es/p/rust-ownership-borrowing-cpp-pointer-comparison/</link><pubDate>Sat, 12 Sep 2026 04:00:00 +0900</pubDate><guid>http://kenji.blog/es/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 Comparando la "Propiedad" y el "Préstamo" de Rust con los Punteros de C++" />&lt;p>En la programación de sistemas moderna, equilibrar el rendimiento y la seguridad de la memoria es un desafío eterno. C++ ha reinado como el rey en este campo durante muchos años, pero recientemente, Rust ha estado amenazando su posición. La mayor característica de Rust radica en los conceptos de &amp;ldquo;Propiedad&amp;rdquo; (Ownership) y &amp;ldquo;Préstamo&amp;rdquo; (Borrowing), que garantizan la seguridad de la memoria en tiempo de compilación sin tener un recolector de basura (GC).&lt;/p>
&lt;p>En este artículo, compararemos en detalle los punteros de C++ (punteros en crudo, &lt;code>std::unique_ptr&lt;/code>, &lt;code>std::shared_ptr&lt;/code>) y el modelo de propiedad de Rust, y explicaremos de manera exhaustiva mediante ejemplos de código y diagramas cómo el compilador de Rust (comprobador de préstamos o borrow checker) evita el uso después de la liberación (Use-After-Free) y las condiciones de carrera de datos (Data Race).&lt;/p>
&lt;h2 id="1-fundamentos-de-la-gestión-de-memoria-pila-y-montículo-stack-and-heap">1. Fundamentos de la gestión de memoria: Pila y Montículo (Stack and Heap)
&lt;/h2>&lt;p>Para entender los conceptos básicos de la gestión de memoria, primero repasemos cómo los programas utilizan la memoria. El espacio de memoria se divide a grandes rasgos en &amp;ldquo;Pila&amp;rdquo; (Stack) y &amp;ldquo;Montículo&amp;rdquo; (Heap).&lt;/p>
&lt;h3 id="pila-stack">Pila (Stack)
&lt;/h3>&lt;p>Es el área donde se apilan las variables locales, etc., cuando se llama a una función. Tiene una estructura LIFO (el último en entrar es el primero en salir), y la asignación y liberación de memoria es extremadamente rápida. Aquí solo se colocan los datos cuyo tamaño se puede determinar en tiempo de compilación.&lt;/p>
&lt;h3 id="montículo-heap">Montículo (Heap)
&lt;/h3>&lt;p>Aquí se colocan los datos cuyo tamaño se determina dinámicamente en tiempo de ejecución, o los datos que necesitan sobrevivir más allá del alcance (scope) de una función. Se accede a través de punteros (o referencias).&lt;/p>
&lt;p>En C++ o Rust, que no tienen recolección de basura, el costo de gestión de la memoria del montículo puede modelarse mediante una fórmula matemática. Si el número total de objetos es $N$, el tiempo promedio de asignación es $T_{alloc}$, y el tiempo promedio de liberación es $T_{dealloc}$, entonces el costo total de gestión de memoria $C_{memory}$ es:&lt;/p>
$$ C_{memory} = \sum_{i=1}^{N} (T_{alloc, i} + T_{dealloc, i}) + O_{sync} $$
&lt;p>Donde $O_{sync}$ es la sobrecarga del control de exclusión (mutexes u operaciones atómicas) en un entorno de múltiples hilos. Como Rust determina el momento de la liberación de memoria en tiempo de compilación, elimina por completo la reducción de rendimiento (Stop-The-World) debido a la recolección de basura en tiempo de ejecución, al tiempo que ejecuta $T_{dealloc}$ en un momento seguro y confiable.&lt;/p>
&lt;div class="mermaid">graph TD
A["Memoria del Programa"] --> B["Pila (Rápida, Tamaño Fijo)"]
A --> C["Montículo (Dinámico, Más lento)"]
B --> D["Variables Locales"]
B --> E["Punteros/Referencias"]
C --> F["Datos Asignados Dinámicamente"]
E -.->|"Apunta a"| F&lt;/div>
&lt;h2 id="2-punteros-en-c-el-compromiso-entre-libertad-y-peligro">2. Punteros en C++: El compromiso entre libertad y peligro
&lt;/h2>&lt;p>Echemos un vistazo a la evolución de la gestión de memoria en C++.&lt;/p>
&lt;h3 id="la-era-de-los-punteros-en-crudo-raw-pointers-y-sus-problemas">La era de los Punteros en Crudo (Raw Pointers) y sus problemas
&lt;/h3>&lt;p>Los punteros en crudo (&lt;code>*&lt;/code>) heredados de C ofrecen la máxima libertad, pero al mismo tiempo son un caldo de cultivo para errores graves como los siguientes:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Fuga de memoria (Memory Leak)&lt;/strong>: Olvidar usar &lt;code>delete&lt;/code> en la memoria asignada con &lt;code>new&lt;/code>.&lt;/li>
&lt;li>&lt;strong>Puntero colgante (Dangling Pointer)&lt;/strong>: Acceder a un puntero después de que la memoria ha sido liberada (después de &lt;code>delete&lt;/code>).&lt;/li>
&lt;li>&lt;strong>Doble liberación (Double Free)&lt;/strong>: Usar &lt;code>delete&lt;/code> dos veces en la misma área de memoria.&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++: Ejemplo de problemas con punteros en crudo
&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">// ... algún procesamiento ...
&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">// Acceso erróneo por segunda vez (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">// El compilador de C++ no puede hacer que esto sea un error de compilación
&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">// Comportamiento indefinido (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="la-llegada-de-raii-y-los-punteros-inteligentes-desde-c11">La llegada de RAII y los Punteros Inteligentes (Desde C++11)
&lt;/h3>&lt;p>A partir de C++11, se estandarizaron los punteros inteligentes basados en el concepto de RAII (Resource Acquisition Is Initialization), y se desaconsejó el uso directo de punteros en crudo.&lt;/p>
&lt;h4 id="stdunique_ptr">&lt;code>std::unique_ptr&lt;/code>
&lt;/h4>&lt;p>Es un puntero que expresa la propiedad única. Cuando sale de su ámbito, la memoria se libera automáticamente. No se puede copiar, solo es posible el &amp;ldquo;movimiento&amp;rdquo; (move) de la propiedad (usando &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; // Error de compilación (no se puede copiar)
&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">// Movimiento de la propiedad
&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">// La debilidad de C++: Después del movimiento, p1 se vuelve nullptr, pero el acceso en sí se puede compilar
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="c1">// Causará un bloqueo (segmentation fault) en tiempo de ejecución
&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>Es un puntero que permite que múltiples punteros compartan el mismo objeto. Utiliza el conteo de referencias (Reference Counting) para liberar la memoria cuando el conteo llega a 0. Dado que requiere operaciones de incremento/decremento atómicas, se produce una ligera sobrecarga de rendimiento (equivalente al $O_{sync}$ mencionado anteriormente).&lt;/p>
&lt;h2 id="3-propiedad-ownership-de-rust-un-cambio-de-paradigma">3. Propiedad (Ownership) de Rust: Un cambio de paradigma
&lt;/h2>&lt;p>Rust ha situado el concepto de &lt;code>std::unique_ptr&lt;/code> de C++ en el núcleo de la especificación del lenguaje, creando un &amp;ldquo;modelo de propiedad&amp;rdquo; mucho más estricto.&lt;/p>
&lt;h3 id="las-3-reglas-de-la-propiedad">Las 3 reglas de la Propiedad
&lt;/h3>&lt;p>El sistema de propiedad de Rust se basa en tres reglas extremadamente simples:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Cada valor en Rust tiene una variable que se llama su propietario (owner).&lt;/strong>&lt;/li>
&lt;li>&lt;strong>Solo puede haber un propietario a la vez.&lt;/strong>&lt;/li>
&lt;li>&lt;strong>Cuando el propietario sale del ámbito, el valor se descarta.&lt;/strong>&lt;/li>
&lt;/ol>
&lt;p>En Rust, los recursos se &amp;ldquo;mueven&amp;rdquo; por defecto. A diferencia de C++, donde se debe especificar &lt;code>std::move&lt;/code>, la propiedad se transfiere simplemente mediante la operación de asignación.&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: Movimiento (move) de la propiedad
&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">// Datos asignados en el montículo
&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 propiedad se mueve de s1 a s2
&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 mayor diferencia con C++: ¡El acceso a la variable después del movimiento es un &amp;#34;error de compilación&amp;#34;!
&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); // Error de compilación: 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>Esta característica de &amp;ldquo;hacer que las variables sean inaccesibles en tiempo de compilación después de un movimiento&amp;rdquo; es una de las razones por las que Rust es más seguro que &lt;code>std::unique_ptr&lt;/code> de C++.&lt;/p>
&lt;div class="mermaid">sequenceDiagram
participant S1 as "Variable s1"
participant Heap as "Memoria del Montículo ('hello')"
participant S2 as "Variable s2"
S1->>Heap: "Asigna y Posee"
Note over S1,S2: "let s2 = s1;"
S1--xHeap: "Pierde la Propiedad (Invalidado)"
S2->>Heap: "Toma la Propiedad"&lt;/div>
&lt;h2 id="4-préstamo-borrowing-y-referencias">4. Préstamo (Borrowing) y Referencias
&lt;/h2>&lt;p>Si la propiedad se mueve constantemente, tendríamos que devolver la propiedad cada vez que pasamos un valor a una función, lo cual es muy inconveniente. Aquí es donde entra el &amp;ldquo;Préstamo&amp;rdquo; (Borrowing). Equivale a los punteros y referencias de C++.&lt;/p>
&lt;p>Hay dos tipos de préstamos en Rust:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Referencia inmutable (Immutable Reference)&lt;/strong>: &lt;code>&amp;amp;T&lt;/code> (Similar a &lt;code>const T&amp;amp;&lt;/code> en C++)&lt;/li>
&lt;li>&lt;strong>Referencia mutable (Mutable Reference)&lt;/strong>: &lt;code>&amp;amp;mut T&lt;/code> (Similar a &lt;code>T&amp;amp;&lt;/code> en C++)&lt;/li>
&lt;/ul>
&lt;h3 id="la-regla-despiadada-del-comprobador-de-préstamos-borrow-checker">La regla despiadada del comprobador de préstamos (Borrow Checker)
&lt;/h3>&lt;p>El compilador de Rust lleva incorporado un &amp;ldquo;comprobador de préstamos&amp;rdquo; que verifica la validez de las referencias. El comprobador de préstamos impone las siguientes reglas estrictas:&lt;/p>
&lt;blockquote>
&lt;p>En cualquier ámbito dado, solo puede existir uno de los siguientes:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Una referencia mutable (&lt;code>&amp;amp;mut T&lt;/code>)&lt;/strong>&lt;/li>
&lt;li>&lt;strong>Múltiples referencias inmutables (&lt;code>&amp;amp;T&lt;/code>)&lt;/strong>&lt;/li>
&lt;/ul>
&lt;/blockquote>
&lt;p>Este es un principio llamado &lt;strong>&amp;ldquo;Múltiple Lectores O un solo Escritor&amp;rdquo; (Multiple Readers XOR Single Writer, MRSW)&lt;/strong>. Puede expresarse matemáticamente usando el O exclusivo (XOR); para un estado $S$, el número de referencias inmutables $N_r$ y el número de referencias mutables $N_w$ deben cumplir con la siguiente restricción:&lt;/p>
$$ (N_r \ge 0 \land N_w = 0) \oplus (N_r = 0 \land N_w = 1) $$
&lt;p>Gracias a esta regla, &lt;strong>se eliminan completamente las condiciones de carrera de datos en tiempo de compilación&lt;/strong>. Una condición de carrera de datos ocurre cuando ① dos o más punteros acceden a los mismos datos simultáneamente, ② al menos uno de ellos realiza una escritura, y ③ no hay un mecanismo de sincronización. Rust previene esto destruyendo la condición ② en tiempo de compilación.&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: Error de compilación por violación de la regla de préstamo
&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">// Préstamo inmutable (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">// Préstamo inmutable (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; // ¡Error! No se puede crear un préstamo mutable si ya existe un préstamo inmutable
&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-prevención-de-la-invalidación-de-iteradores-iterator-invalidation">5. Prevención de la invalidación de iteradores (Iterator Invalidation)
&lt;/h2>&lt;p>Veamos un error clásico, la &amp;ldquo;invalidación de iteradores&amp;rdquo;, como un ejemplo concreto donde el poder del comprobador de préstamos brilla más.&lt;/p>
&lt;h3 id="invalidación-de-iteradores-en-c-bloqueo-en-tiempo-de-ejecución">Invalidación de iteradores en C++ (Bloqueo en tiempo de ejecución)
&lt;/h3>&lt;p>Si se modifica un &lt;code>std::vector&lt;/code> de C++ durante un bucle, es posible que la memoria subyacente se reasigne, convirtiendo las referencias en punteros colgantes.&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++: El error de la invalidación de iteradores
&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">// Obtener una referencia a un elemento del vector
&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">// Agregar un elemento (Si no hay capacidad suficiente aquí, se asigna una nueva área de memoria,
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="c1">// y la antigua área puede ser descartada)
&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 podría estar apuntando a memoria ya liberada! (Comportamiento indefinido)
&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;The first element is: &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="defensa-en-tiempo-de-compilación-por-rust">Defensa en tiempo de compilación por Rust
&lt;/h3>&lt;p>Escribamos exactamente la misma lógica 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: Prevención de la invalidación de iteradores en tiempo de compilación
&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">// Obtener una referencia inmutable (Inicio del préstamo)
&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">// ¡Error! Mientras `first` tenga un préstamo inmutable de `v`,
&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">// no se puede realizar el préstamo mutable requerido por `v.push`.
&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;The first element is: &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>De esta manera, en Rust, &amp;ldquo;modificar un valor (préstamo mutable) mientras se está leyendo (préstamo inmutable)&amp;rdquo; está prohibido a nivel del compilador, por lo que errores fatales como el uso después de la liberación (Use-After-Free) y la invalidación de iteradores se capturan de forma fiable en tiempo de compilación.&lt;/p>
&lt;div class="mermaid">graph LR
A["Variable v (Propietario)"] --> B["Matriz en el Montículo [1, 2, 3]"]
C["Referencia 'first' (&amp;v[0])"] -.->|"Préstamo Inmutable"| B
A -->|X "¡Préstamo Mutable Denegado!"| D["v.push(4)"]
style C stroke:#00FF00,stroke-width:2px
style D stroke:#FF0000,stroke-width:2px&lt;/div>
&lt;h2 id="6-propiedad-compartida-en-rust-rc-y-arc">6. Propiedad Compartida en Rust: &lt;code>Rc&lt;/code> y &lt;code>Arc&lt;/code>
&lt;/h2>&lt;p>Rust también proporciona una propiedad compartida equivalente a &lt;code>std::shared_ptr&lt;/code> de C++, pero separa claramente los tipos para uso en un solo hilo y para uso en múltiples hilos.&lt;/p>
&lt;h3 id="para-un-solo-hilo-rct-reference-counted">Para un solo hilo: &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> es un puntero inteligente de conteo de referencias no seguro para hilos (non-thread-safe). Ya que incrementa y decrementa el conteo sin utilizar instrucciones atómicas, es extremadamente rápido dentro de un solo hilo. Sin embargo, si intentas enviarlo a otro hilo, resultará en un error de compilación (porque no implementa el rasgo &lt;code>Send&lt;/code>).&lt;/p>
&lt;h3 id="para-múltiples-hilos-arct-atomic-reference-counted">Para múltiples hilos: &lt;code>Arc&amp;lt;T&amp;gt;&lt;/code> (Atomic Reference Counted)
&lt;/h3>&lt;p>Cuando se comparte entre hilos, se usa &lt;code>Arc&amp;lt;T&amp;gt;&lt;/code>, que realiza incrementos y decrementos de manera atómica. Tiene un costo equivalente a &lt;code>std::shared_ptr&lt;/code> de C++.&lt;/p>
&lt;p>Además, en C++, si varios hilos escriben simultáneamente en una variable compartida mediante &lt;code>std::shared_ptr&lt;/code>, se producirá una condición de carrera de datos. Para prevenir esto, es necesario usar &lt;code>std::mutex&lt;/code> manualmente de forma correcta.&lt;/p>
&lt;p>Por otro lado, en Rust, &lt;strong>no se pueden modificar los datos internos&lt;/strong> solo con &lt;code>Arc&amp;lt;T&amp;gt;&lt;/code>. Si se necesita modificar, debe combinarse con &lt;code>Mutex&amp;lt;T&amp;gt;&lt;/code>, que es un mutex.&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">// Combinación de recursos compartidos seguros para hilos y control de exclusión
&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">// Similar a std::shared_ptr&amp;lt;std::mutex&amp;gt; de C++, pero el Mutex encierra los datos
&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">// Solo puedes obtener la referencia mutable interna (&amp;amp;mut i32) llamando a lock()
&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">// El bloqueo se libera automáticamente mediante RAII cuando sale del ámbito
&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;Result: &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>Lo que cabe destacar es que el &lt;code>Mutex&amp;lt;T&amp;gt;&lt;/code> de Rust no es solo un mecanismo de bloqueo, sino que &lt;strong>&amp;ldquo;encapsula los datos a proteger como un tipo&amp;rdquo;&lt;/strong>. Esto evita completamente a nivel de compilación el error de &amp;ldquo;acceder a los datos olvidando tomar el bloqueo&amp;rdquo;. El sistema está diseñado para que no puedas obtener el derecho de acceso (referencia) a los datos internos a menos que adquieras el bloqueo (&lt;code>lock()&lt;/code>).&lt;/p>
&lt;h2 id="conclusión-inspección-previa-por-parte-del-compilador-o-responsabilidad-propia-por-parte-del-desarrollador">Conclusión: ¿&amp;ldquo;Inspección previa&amp;rdquo; por parte del compilador o &amp;ldquo;responsabilidad propia&amp;rdquo; por parte del desarrollador?
&lt;/h2>&lt;p>Los punteros y los punteros inteligentes de C++ proporcionan un alto grado de control y rendimiento a los desarrolladores, pero su uso correcto depende de la disciplina del desarrollador. Aunque la introducción de RAII y &lt;code>std::unique_ptr&lt;/code> hizo que C++ fuera drásticamente más seguro, aún no puede prevenir por completo comportamientos indefinidos como el acceso después del movimiento y la invalidación de iteradores a nivel del lenguaje.&lt;/p>
&lt;p>Por otro lado, Rust detecta estos errores en &lt;strong>tiempo de compilación&lt;/strong> en lugar de en tiempo de ejecución, incorporando las reglas de Propiedad (Ownership) y Préstamo (Borrowing) en el compilador. Esta fuerte garantía de que &amp;ldquo;si compila, es seguro para la memoria&amp;rdquo; es la razón principal por la que Rust está ganando apoyo rápidamente en la programación de sistemas.&lt;/p>
&lt;p>Luchar contra el comprobador de préstamos de Rust (Fight the borrow checker) puede ser un gran obstáculo para los principiantes, pero no es más que el compilador asumiendo estrictamente el cálculo complejo de &amp;ldquo;rastrear la vida útil del puntero&amp;rdquo; que los programadores de C++ tradicionalmente hacían en sus cabezas.&lt;/p>
&lt;p>Si aprendes Rust después de entender la libertad y el peligro de los punteros en C++, deberías poder comprender más profundamente la filosofía detrás del modelo de propiedad: &amp;ldquo;por qué se diseñó de esta manera&amp;rdquo;.&lt;/p>
&lt;hr>
&lt;p>&lt;em>Este artículo es un estudio comparativo sobre los métodos de gestión de memoria en C++ y Rust. Esperamos que te sirva de referencia para elegir el lenguaje adecuado según los requisitos de tu proyecto.&lt;/em>&lt;/p></description></item><item><title>Ventajas y desventajas de aprender Rust como ingeniero de C++</title><link>http://kenji.blog/es/p/cpp-engineer-learning-rust-pros-cons/</link><pubDate>Sat, 12 Sep 2026 03:00:00 +0900</pubDate><guid>http://kenji.blog/es/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 Ventajas y desventajas de aprender Rust como ingeniero de C++" />&lt;h1 id="introducción-un-nuevo-amanecer-en-la-programación-de-sistemas">Introducción: Un nuevo amanecer en la programación de sistemas
&lt;/h1>&lt;p>En la ingeniería de software moderna, C++ y Rust son los dos gigantes que lideran la vanguardia de la programación de sistemas. Durante muchos años, C++ ha reinado como el rey absoluto en áreas que extraen el máximo rendimiento del hardware, como sistemas operativos, dispositivos embebidos, motores de juegos y sistemas de comercio de alta frecuencia (HFT). Como ingeniero senior de C++, yo mismo he estado escribiendo código a lo largo de este viaje, empezando por la jungla de los punteros crudos en la era de C++98, pasando por la ola de modernización con C++11 (introducción de punteros inteligentes, expresiones lambda, &lt;code>auto&lt;/code>), y continuando con la expansión masiva de las especificaciones en C++14/17/20.&lt;/p>
&lt;p>Sin embargo, en los últimos años, Rust ha experimentado un ascenso dramático como solución a los problemas estructurales que enfrenta C++: específicamente la &amp;ldquo;falta de seguridad de memoria&amp;rdquo; que conduce a vulnerabilidades de seguridad (se dice que alrededor del 70% de los CVE son causados por la memoria) y la &amp;ldquo;complejidad interminable de especificaciones y comportamientos indefinidos (UB)&amp;rdquo;. Su adopción oficial en el kernel de Linux, y los proyectos de migración a gran escala a Rust por gigantes tecnológicos como Microsoft, Google y AWS, significan que no es solo una moda pasajera, sino un cambio de paradigma en la programación de sistemas.&lt;/p>
&lt;p>En este artículo, compararé y explicaré exhaustivamente desde un punto de vista técnico y fundamental las &amp;ldquo;ventajas&amp;rdquo; y &amp;ldquo;desventajas&amp;rdquo; que un ingeniero de C++ puro ha experimentado al aprender profundamente Rust y usarlo en la práctica.&lt;/p>
&lt;hr>
&lt;h1 id="1-el-cambio-de-paradigma-en-la-gestión-de-memoria-de-raii-a-ownership-y-borrowing">1. El cambio de paradigma en la gestión de memoria: de RAII a Ownership y Borrowing
&lt;/h1>&lt;h2 id="raii-en-c-y-los-límites-de-los-punteros-inteligentes">RAII en C++ y los límites de los punteros inteligentes
&lt;/h2>&lt;p>Una de las mayores invenciones de C++ es &lt;strong>RAII (Resource Acquisition Is Initialization)&lt;/strong>. Este concepto, que consiste en asegurar los recursos en el constructor y liberarlos automáticamente en el destructor al salir del alcance (scope), liberó a los desarrolladores del temor a las fugas de memoria causadas por el uso manual de &lt;code>new&lt;/code> y &lt;code>delete&lt;/code>. A partir de C++11, se introdujeron &lt;code>std::unique_ptr&lt;/code> y &lt;code>std::shared_ptr&lt;/code> en la biblioteca estándar, lo que permitió expresar el concepto de propiedad (Ownership) en el código.&lt;/p>
&lt;p>Sin embargo, los punteros inteligentes y la semántica de movimiento de C++ tienen una debilidad fatal: la verificación estática por parte del compilador es incompleta.&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">// Mover (Move) la propiedad a la función
&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">// Peligro: En C++, acceder a un objeto después del movimiento no causa un error de compilación
&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 es simplemente un cast a una referencia rvalue (T&amp;amp;&amp;amp;), y el compilador no bloquea su uso
&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; // Comportamiento indefinido por el uso de memoria después de ser liberada (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++, siempre existe el riesgo de acceder por error a un objeto que ha sido vaciado por &lt;code>std::move&lt;/code> (un estado válido pero no especificado). Esto puede provocar bloqueos (crashes) en tiempo de ejecución o, en el peor de los casos, directamente vulnerabilidades de seguridad.&lt;/p>
&lt;h2 id="propiedad-ownership-en-rust-y-la-defensa-absoluta-del-borrow-checker">Propiedad (Ownership) en Rust y la defensa absoluta del Borrow Checker
&lt;/h2>&lt;p>Rust incorpora este concepto de &amp;ldquo;propiedad&amp;rdquo; en el diseño central del lenguaje, y realiza un análisis estático estricto mediante una característica del compilador llamada &lt;strong>Borrow Checker&lt;/strong>.&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">// Aquí s sale del alcance, y la memoria es liberada (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">// Mover la propiedad a la función. En Rust, la semántica de movimiento es el valor por defecto.
&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">// ¡Error de compilación! Es absolutamente imposible acceder a la variable después de ser movida
&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, en el momento en que se transfiere la propiedad de una variable, el compilador trata a la variable original de manera equivalente a un estado &amp;ldquo;no inicializado&amp;rdquo;, bloqueando completamente cualquier acceso posterior. Debido a esto, errores como &amp;ldquo;Use-After-Free (Uso de memoria después de ser liberada)&amp;rdquo; y &amp;ldquo;Dangling Pointer (Puntero colgante)&amp;rdquo; teóricamente no pueden pasar la compilación.&lt;/p>
&lt;div class="mermaid">graph TD
A["C++ std::unique_ptr"] --> B["std::move aplicado"]
B --> C["Propiedad transferida"]
C --> D["El puntero antiguo sigue siendo accesible"]
D --> E["Posible comportamiento indefinido (UB)"]
F["Rust Box / String"] --> G["Pasado por valor (Move)"]
G --> H["Propiedad transferida"]
H --> I["El compilador bloquea la variable antigua"]
I --> J["Seguridad de memoria garantizada"]&lt;/div>
&lt;h2 id="préstamo-borrowing-y-control-de-mutabilidad">Préstamo (Borrowing) y control de mutabilidad
&lt;/h2>&lt;p>Aún más poderosas son las reglas de &amp;ldquo;Préstamo (Borrowing)&amp;rdquo; que referencian recursos. En Rust se imponen las siguientes reglas:&lt;/p>
&lt;ol>
&lt;li>En cualquier momento, &lt;strong>solo puede existir uno&lt;/strong> de los siguientes casos: &amp;ldquo;Múltiples referencias inmutables (&lt;code>&amp;amp;T&lt;/code>)&amp;rdquo; o &amp;ldquo;Una única referencia mutable (&lt;code>&amp;amp;mut T&lt;/code>)&amp;rdquo;.&lt;/li>
&lt;li>Una referencia no debe vivir más tiempo que el alcance de los datos originales (restricción de tiempo de vida - lifetime).&lt;/li>
&lt;/ol>
&lt;p>En C++, se pueden crear fácilmente múltiples referencias o punteros mutables para el mismo objeto, lo que provoca la destrucción de estados inesperados (como la invalidación de iteradores). Rust prohíbe esta combination de &amp;ldquo;Aliasing + Mutabilidad&amp;rdquo; a nivel de lenguaje para prevenir errores antes de que ocurran.&lt;/p>
&lt;hr>
&lt;h1 id="2-diseño-de-memoria-y-la-sobrecarga-matemática-de-los-punteros-inteligentes">2. Diseño de memoria y la sobrecarga matemática de los punteros inteligentes
&lt;/h1>&lt;p>En la programación de sistemas, es esencial tener una comprensión precisa del diseño de la memoria. Comparemos &lt;code>std::shared_ptr&lt;/code> de C++ con &lt;code>std::rc::Rc&lt;/code> / &lt;code>std::sync::Arc&lt;/code> de Rust.&lt;/p>
&lt;p>&lt;code>std::shared_ptr&lt;/code> en C++ gestiona los recursos mediante conteo de referencias, y por defecto aumenta y disminuye este conteo utilizando operaciones atómicas thread-safe (&lt;code>std::atomic&lt;/code>). Su sobrecarga de memoria se puede formular de la siguiente manera:&lt;/p>
$$ Overhead_{C++} = sizeof(T) + sizeof(ControlBlock) $$
&lt;p>Aquí, el $ControlBlock$ incluye el &amp;ldquo;Contador de referencias fuertes (Strong Ref Count)&amp;rdquo;, el &amp;ldquo;Contador de referencias débiles (Weak Ref Count)&amp;rdquo; y un &amp;ldquo;Eliminador personalizado (Custom Deleter)&amp;rdquo;. El problema es que, incluso en escenarios donde solo se usa un hilo (single-thread), la sobrecarga de las instrucciones atómicas (bloqueos en la línea de caché, etc.) ocurre incondicionalmente.&lt;/p>
&lt;p>En contraste, Rust separa estrictamente los punteros inteligentes según su caso de uso.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Para un solo hilo&lt;/strong>: &lt;code>Rc&amp;lt;T&amp;gt;&lt;/code> (Reference Counted)&lt;/li>
&lt;li>&lt;strong>Para múltiples hilos&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 se usa &lt;code>Rc&amp;lt;T&amp;gt;&lt;/code>, que es exclusivo para un solo hilo, se puede evitar por completo la penalización de las operaciones atómicas (abstracción de costo cero). Y gracias al mecanismo de seguridad de hilos (thread-safety) que veremos más adelante, pasar &lt;code>Rc&amp;lt;T&amp;gt;&lt;/code> a otro hilo por error es completamente prevenido por el sistema de tipos.&lt;/p>
&lt;hr>
&lt;h1 id="3-seguridad-de-hilos-thread-safety-el-impacto-de-fearless-concurrency">3. Seguridad de hilos (Thread-Safety): El impacto de &amp;ldquo;Fearless Concurrency&amp;rdquo;
&lt;/h1>&lt;p>En C++, la programación multihilo siempre ha estado acompañada del miedo a las condiciones de carrera (data races) y los bloqueos (deadlocks).&lt;/p>
&lt;h2 id="peligros-de-los-mutex-en-c-y-la-separación-de-datos">Peligros de los Mutex en C++ y la separación de datos
&lt;/h2>&lt;p>El &lt;code>std::mutex&lt;/code> en C++ es simplemente para controlar la exclusividad en &amp;ldquo;un bloque de código específico (sección crítica)&amp;rdquo;, y no existe ningún vínculo a nivel de lenguaje entre &amp;ldquo;los datos que se deben proteger&amp;rdquo; y el &amp;ldquo;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">// Incluso si el desarrollador olvida adquirir el bloqueo, compilará sin problemas
&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">// ¡Condición de carrera fatal!
&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="en-rust-mutex-posee-los-datos">En Rust, Mutex &amp;ldquo;posee&amp;rdquo; los datos
&lt;/h2>&lt;p>En Rust, &lt;code>Mutex&amp;lt;T&amp;gt;&lt;/code> utiliza genéricos para &lt;strong>encapsular (poseer)&lt;/strong> el tipo de dato &lt;code>T&lt;/code> que protege. Para acceder a los datos, es absolutamente necesario invocar &lt;code>lock()&lt;/code> y obtener un objeto guardia (guard object). Es sintácticamente imposible tocar los datos sin obtener el bloqueo.&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">// Los datos están completamente encapsulados dentro del 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">// Clonar Arc (conteo de referencias seguro para hilos) para compartirlo entre hilos
&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">// No se puede acceder al Vec interno a menos que se adquiera el bloqueo
&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>Además, Rust cuenta con dos traits centrales que garantizan la seguridad del procesamiento concurrente.&lt;/p>
&lt;ul>
&lt;li>&lt;code>Send&lt;/code>: Tipos cuya propiedad puede transferirse de forma segura entre hilos.&lt;/li>
&lt;li>&lt;code>Sync&lt;/code>: Tipos a los que se puede acceder simultáneamente desde varios hilos de forma segura.&lt;/li>
&lt;/ul>
&lt;p>Por ejemplo, &lt;code>Rc&amp;lt;T&amp;gt;&lt;/code>, que no es seguro para hilos, no implementa el trait &lt;code>Send&lt;/code>. Por lo tanto, intentar pasarlo a &lt;code>thread::spawn&lt;/code> resulta en un error de compilación instantáneo. Gracias a esta &amp;ldquo;Fearless Concurrency&amp;rdquo; (Concurrencia sin miedo), los desarrolladores se liberan del temor a los errores y pueden promover la paralelización de forma más agresiva.&lt;/p>
&lt;p>Según la Ley de Amdahl (Amdahl&amp;rsquo;s Law), el rendimiento máximo teórico en relación a la parte paralelizable $P$ y el grado de paralelismo $N$ se expresa de la siguiente manera:&lt;/p>
$$ S(N) = \frac{1}{(1 - P) + \frac{P}{N}} $$
&lt;p>Rust permite maximizar esta $P$ a través de refactorizaciones que pueden realizarse con extrema seguridad basándose en el sistema de tipos.&lt;/p>
&lt;div class="mermaid">graph TD
A["Seguridad de hilos en C++"] --> B["Depende de la memoria del desarrollador"]
B --> C["Mutex desacoplado de los datos"]
C --> D["Alto riesgo de condiciones de carrera silenciosas"]
E["Seguridad de hilos en Rust"] --> F["Traits Send y Sync"]
F --> G["Mutex posee los datos"]
G --> H["Condiciones de carrera prevenidas en tiempo de compilación"]&lt;/div>
&lt;hr>
&lt;h1 id="4-manejo-de-errores-excepciones-vs-tipos-de-datos-algebraicos">4. Manejo de errores: Excepciones vs Tipos de Datos Algebraicos
&lt;/h1>&lt;p>El estándar de manejo de errores en C++ son las &amp;ldquo;Excepciones&amp;rdquo; (Exceptions). Sin embargo, las excepciones opacan el flujo de control y provocan penalizaciones de rendimiento (stack unwinding y sobrecarga de RTTI). En los sistemas embebidos y en los motores de juegos, suele ser común adoptar un diseño que devuelve códigos de error clásicos y deshabilita completamente las excepciones (&lt;code>-fno-exceptions&lt;/code>). En C++23 se introdujo &lt;code>std::expected&lt;/code>, pero tomará tiempo hasta que penetre en todo el ecosistema.&lt;/p>
&lt;p>En Rust, el concepto de excepción no existe. Los errores se devuelven como &amp;ldquo;valores&amp;rdquo; puros y se representan mediante un enum (tipo de dato algebraico) llamado &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">// Con solo mirar el tipo de retorno, queda claro que puede ocurrir un error de IO
&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">// Con el operador ?, si hay un error, hace un retorno anticipado inmediato, si es un éxito, extrae el contenido
&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>Este operador &lt;code>?&lt;/code> es revolucionario. Elimina la profunda anidación (pirámide de if) que ocurre al comprobar los códigos de error en C++, manteniendo un flujo de código limpio como el de las excepciones, a la vez que permite describir explícitamente en qué llamadas a funciones se propagan los errores.&lt;/p>
&lt;hr>
&lt;h1 id="5-polimorfismo-de-funciones-virtuales-y-plantillas-a-traits">5. Polimorfismo: De Funciones Virtuales y Plantillas a Traits
&lt;/h1>&lt;p>El polimorfismo en C++ se logra principalmente a través del despacho dinámico (dynamic dispatch) mediante herencia de clases y funciones virtuales (&lt;code>virtual&lt;/code>), o despacho estático mediante plantillas (CRTP, etc.).&lt;/p>
&lt;p>En el despacho dinámico, se inserta un puntero (vptr) a la tabla de funciones virtuales (vtable) en el objeto, lo que provoca una sobrecarga en la resolución del puntero al invocar la función.&lt;/p>
$$ T_{dispatch} = T_{lookup\_in\_vtable} + T_{dereference} $$
&lt;p>Rust ha descartado la clásica &amp;ldquo;herencia de clases&amp;rdquo; orientada a objetos, adoptando en su lugar el concepto de &amp;ldquo;&lt;strong>Traits&lt;/strong>&amp;rdquo; (similar a Concept de C++20, pero con más funcionalidades).&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">// Despacho estático (Monomorfización, costo cero de sobrecarga)
&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">// Despacho dinámico (Objetos 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 característica principal del despacho dinámico de Rust (&lt;code>dyn Trait&lt;/code>) es que no tiene un vptr dentro de la estructura de datos, sino que utiliza un &lt;strong>Puntero Gordo (Fat Pointer)&lt;/strong>. El Fat Pointer mantiene un par con el &amp;ldquo;puntero a los datos&amp;rdquo; y el &amp;ldquo;puntero a la vtable&amp;rdquo;. Gracias a esto, es muy fácil implementar (extender) un Trait a un tipo definido en una biblioteca externa y aplicarle el despacho dinámico posteriormente.&lt;/p>
&lt;hr>
&lt;h1 id="6-gestión-de-paquetes-y-sistema-de-construcción-la-agonía-de-cmake-y-las-bendiciones-de-cargo">6. Gestión de paquetes y sistema de construcción: La agonía de CMake y las bendiciones de Cargo
&lt;/h1>&lt;p>Una de las mayores debilidades de C++ es la falta de un administrador de paquetes estándar. La sintaxis incomprensible de &lt;code>CMakeLists.txt&lt;/code>, la complejidad para resolver dependencias a través de &lt;code>find_package&lt;/code>, y las diferencias en las rutas de las bibliotecas según el sistema operativo, han estado robando una enorme cantidad de tiempo a los ingenieros de C++.&lt;/p>
&lt;p>Rust viene equipado de serie con &lt;strong>Cargo&lt;/strong>, un sistema de construcción y administrador de paquetes de primer nivel a nivel mundial.&lt;/p>
&lt;div class="mermaid">graph TD
A["Entorno de construcción de C++"] --> B["CMakeLists.txt"]
B --> C["Integración de vcpkg / Conan"]
C --> D["Generar Makefiles / Ninja"]
D --> E["Compilador (GCC/Clang/MSVC)"]
F["Entorno de construcción de Rust"] --> G["Cargo.toml"]
G --> H["Obtener dependencias de crates.io"]
H --> I["rustc (Cargo build)"]
I --> J["Binario listo para ejecutar"]&lt;/div>
&lt;p>Con solo agregar una línea en &lt;code>Cargo.toml&lt;/code> con el nombre y la versión de la biblioteca dependiente (crate), se resuelve, descarga y compila de forma totalmente automática, incluyendo sus dependencias transitivas. Además, herramientas esenciales para el desarrollo como pruebas (&lt;code>cargo test&lt;/code>), generación de documentación (&lt;code>cargo doc&lt;/code>), análisis estático (&lt;code>cargo clippy&lt;/code>) y formateador (&lt;code>cargo fmt&lt;/code>) están completamente integradas en este único comando. Esta comodidad es tan disruptiva que, una vez que la experimentas, no querrás volver al entorno de construcción de C++.&lt;/p>
&lt;hr>
&lt;h1 id="7-desventajas-y-curva-de-aprendizaje-al-aprender-rust">7. Desventajas y curva de aprendizaje al aprender Rust
&lt;/h1>&lt;p>Hasta ahora, he hablado de las ventajas de Rust, pero ciertamente existen &amp;ldquo;muros&amp;rdquo; y desventajas que un ingeniero de C++ enfrentará al implementarlo en la práctica.&lt;/p>
&lt;h2 id="1-la-feroz-lucha-con-el-borrow-checker">1. La feroz lucha con el Borrow Checker
&lt;/h2>&lt;p>Si intentas implementar de la misma manera en Rust una estructura de datos que en C++ simplemente &amp;ldquo;conectabas de alguna manera con punteros crudos&amp;rdquo; (por ejemplo, listas doblemente enlazadas, estructuras de grafos, estructuras autorreferenciadas, etc.), la compilación fallará debido a las restricciones de propiedad y tiempos de vida. Para satisfacer al Borrow Checker, necesitas hacer envolturas complejas como &lt;code>Rc&amp;lt;RefCell&amp;lt;T&amp;gt;&amp;gt;&lt;/code>, o rediseñar desde la raíz usando un asignador de arena (arena allocator) o una gestión basada en índices.&lt;/p>
&lt;h2 id="2-largos-tiempos-de-compilación">2. Largos tiempos de compilación
&lt;/h2>&lt;p>Aunque C++ también ralentiza la compilación al anidar plantillas, el tiempo de compilación de Rust (especialmente en un clean build desde cero) no es para nada corto. Esto se debe a la superposición de las potentes pasadas de optimización de LLVM, la expansión de macros y la monomorfización de genéricos, lo que convierte al tiempo de construcción en un cuello de botella en proyectos a gran escala. Durante el desarrollo, es indispensable ingeniárselas usando &lt;code>cargo check&lt;/code> con frecuencia.&lt;/p>
&lt;h2 id="3-interoperabilidad-con-bases-de-código-de-c">3. Interoperabilidad con bases de código de C++
&lt;/h2>&lt;p>La integración con el lenguaje C (FFI) es muy fluida, pero integrar Rust directamente en bases de código enormes de C++ existentes (aquellas que utilizan en gran medida clases, plantillas y funciones virtuales) es extremadamente difícil. En los últimos años, han evolucionado herramientas puente como &lt;code>cxx&lt;/code> y &lt;code>autocxx&lt;/code>, pero todavía hay un listón alto para una transición completamente fluida.&lt;/p>
&lt;hr>
&lt;h1 id="conclusión-deberíamos-migrar-a-rust">Conclusión: ¿Deberíamos migrar a Rust?
&lt;/h1>&lt;p>C++ seguirá desempeñando un papel importante en el desarrollo de motores de juegos y en la enorme infraestructura existente. Su modernización a través de C++20/23 también ha sido notable, volviéndose más seguro de escribir.&lt;/p>
&lt;p>Sin embargo, para &amp;ldquo;proyectos de programación de sistemas creados desde cero&amp;rdquo;, siento que hoy en día &lt;strong>es más difícil encontrar razones para no elegir Rust&lt;/strong>. Una vez que pasas la compilación, te liberas del miedo a los comportamientos indefinidos y a la corrupción de memoria, y puedes ejecutar un procesamiento concurrente seguro y con alto rendimiento; esta &amp;ldquo;certeza&amp;rdquo; de Rust mejora drásticamente el modelo mental del ingeniero.&lt;/p>
&lt;p>Para los ingenieros de C++, aprender Rust no es solo memorizar una nueva sintaxis, sino la mejor experiencia para adquirir una nueva perspectiva sobre &amp;ldquo;cómo gestionar de forma segura la memoria y los hilos&amp;rdquo;. Te invito a experimentar la comodidad de Cargo y la severidad del Borrow Checker.&lt;/p></description></item></channel></rss>