<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Ownership on kenji.blog</title><link>http://kenji.blog/ar/tags/ownership/</link><description>Recent content in Ownership on kenji.blog</description><generator>Hugo -- gohugo.io</generator><language>ar</language><copyright>kenjinote</copyright><lastBuildDate>Sat, 12 Sep 2026 04:00:00 +0900</lastBuildDate><atom:link href="http://kenji.blog/ar/tags/ownership/index.xml" rel="self" type="application/rss+xml"/><item><title>شرح "الملكية" و"الاستعارة" في Rust مقارنة بمؤشرات C++</title><link>http://kenji.blog/ar/p/rust-ownership-borrowing-cpp-pointer-comparison/</link><pubDate>Sat, 12 Sep 2026 04:00:00 +0900</pubDate><guid>http://kenji.blog/ar/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 شرح "الملكية" و"الاستعارة" في Rust مقارنة بمؤشرات C++" />&lt;p>في برمجة الأنظمة الحديثة، يمثل تحقيق التوازن بين الأداء وأمان الذاكرة تحديًا مستمرًا. لفترة طويلة، سيطرت C++ على هذا المجال كملك متوج، ولكن في السنوات الأخيرة، بدأت لغة Rust في تهديد هذه المكانة. تتمثل الميزة الأبرز في Rust في مفهومي &amp;ldquo;الملكية (Ownership)&amp;rdquo; و&amp;quot;الاستعارة (Borrowing)&amp;quot;، اللذين يضمنان أمان الذاكرة في وقت الترجمة دون الحاجة إلى جامع قمامة (Garbage Collection).&lt;/p>
&lt;p>في هذه المقالة، سنقارن بالتفصيل بين مؤشرات C++ (المؤشرات الخام، &lt;code>std::unique_ptr&lt;/code>، &lt;code>std::shared_ptr&lt;/code>) ونموذج الملكية في Rust. سنشرح بشكل شامل كيف يمنع مترجم Rust (مدقق الاستعارة أو Borrow Checker) أخطاء مثل الاستخدام بعد التحرير (Use-After-Free) وسباق البيانات (Data Race)، وذلك مدعومًا بأمثلة برمجية ورسوم توضيحية.&lt;/p>
&lt;h2 id="1-أساسيات-إدارة-الذاكرة-المكدس-stack-والكومة-heap">1. أساسيات إدارة الذاكرة: المكدس (Stack) والكومة (Heap)
&lt;/h2>&lt;p>لفهم أساسيات إدارة الذاكرة، دعونا نراجع أولاً كيف يستخدم البرنامج الذاكرة. تنقسم مساحة الذاكرة بشكل رئيسي إلى &amp;ldquo;المكدس (Stack)&amp;rdquo; و&amp;quot;الكومة (Heap)&amp;quot;.&lt;/p>
&lt;h3 id="المكدس-stack">المكدس (Stack)
&lt;/h3>&lt;p>هي المنطقة التي يتم فيها تكديس المتغيرات المحلية وغيرها عند استدعاء الدوال. تتميز بهيكل LIFO (ما يدخل أخيرًا يخرج أولاً)، وتكون عملية تخصيص الذاكرة وتحريرها سريعة جدًا. يتم وضع البيانات التي يمكن تحديد حجمها في وقت الترجمة (Compile time) فقط هنا.&lt;/p>
&lt;h3 id="الكومة-heap">الكومة (Heap)
&lt;/h3>&lt;p>يتم فيها وضع البيانات التي يُحدد حجمها ديناميكيًا في وقت التشغيل (Runtime)، أو البيانات التي تحتاج إلى البقاء بعد انتهاء نطاق الدالة (Scope). يتم الوصول إليها عبر المؤشرات (Pointers) أو المراجع (References).&lt;/p>
&lt;p>في اللغات التي لا تحتوي على جامع قمامة مثل C++ وRust، يمكن صياغة تكلفة إدارة ذاكرة الكومة بمعادلة رياضية كالتالي. بافتراض أن إجمالي عدد الكائنات هو $N$، ومتوسط الوقت المستغرق في التخصيص هو $T_{alloc}$، ومتوسط الوقت المستغرق في التحرير هو $T_{dealloc}$، فإن إجمالي تكلفة إدارة الذاكرة $C_{memory}$ يكون:&lt;/p>
$$ C_{memory} = \sum_{i=1}^{N} (T_{alloc, i} + T_{dealloc, i}) + O_{sync} $$
&lt;p>حيث يمثل $O_{sync}$ النفقات الإضافية (Overhead) للتحكم الحصري (مثل كائنات المزامنة Mutex والعمليات الذرية Atomic operations) في بيئة متعددة الخيوط (Multithreaded). نظرًا لأن Rust تحدد توقيت تحرير الذاكرة في وقت الترجمة، فإنها تقضي على مشكلة انخفاض الإنتاجية (Stop-The-World) الناتجة عن جامع القمامة في وقت التشغيل، وتنفذ $T_{dealloc}$ في وقت آمن ومؤكد.&lt;/p>
&lt;div class="mermaid">graph TD
A["ذاكرة البرنامج"] --> B["المكدس (سريع، حجم ثابت)"]
A --> C["الكومة (ديناميكي، أبطأ)"]
B --> D["المتغيرات المحلية"]
B --> E["المؤشرات/المراجع"]
C --> F["بيانات مخصصة ديناميكيًا"]
E -.->|"يشير إلى"| F&lt;/div>
&lt;h2 id="2-مؤشرات-c-مقايضة-بين-الحرية-والخطر">2. مؤشرات C++: مقايضة بين الحرية والخطر
&lt;/h2>&lt;p>دعونا نلقي نظرة على تطور إدارة الذاكرة في C++.&lt;/p>
&lt;h3 id="عصر-المؤشرات-الخام-raw-pointers-ومشاكلها">عصر المؤشرات الخام (Raw Pointers) ومشاكلها
&lt;/h3>&lt;p>توفر المؤشرات الخام (&lt;code>*&lt;/code>)، الموروثة من لغة C، حرية مطلقة، ولكنها في الوقت نفسه تعتبر بيئة خصبة لأخطاء خطيرة مثل:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>تسرب الذاكرة (Memory Leak)&lt;/strong>: نسيان استخدام &lt;code>delete&lt;/code> للذاكرة المخصصة بواسطة &lt;code>new&lt;/code>.&lt;/li>
&lt;li>&lt;strong>المؤشرات المتدلية (Dangling Pointer)&lt;/strong>: الوصول إلى مؤشر يشير إلى ذاكرة تم تحريرها (بعد &lt;code>delete&lt;/code>).&lt;/li>
&lt;li>&lt;strong>التحرير المزدوج (Double Free)&lt;/strong>: استخدام &lt;code>delete&lt;/code> لنفس مساحة الذاكرة مرتين.&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++: مثال على المشاكل الناجمة عن المؤشرات الخام
&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">// ... بعض العمليات ...
&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">// الوصول عن طريق الخطأ مرة أخرى (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">// لا يستطيع مترجم C++ تحويل هذا إلى خطأ في وقت الترجمة
&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">// سلوك غير محدد (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="ظهور-raii-والمؤشرات-الذكية-بداية-من-c11">ظهور RAII والمؤشرات الذكية (بداية من C++11)
&lt;/h3>&lt;p>منذ C++11، تم توحيد المؤشرات الذكية المبنية على مفهوم RAII (اكتساب الموارد هو التهيئة)، وأصبح الاستخدام المباشر للمؤشرات الخام غير محبذ.&lt;/p>
&lt;h4 id="stdunique_ptr">&lt;code>std::unique_ptr&lt;/code>
&lt;/h4>&lt;p>مؤشر يمثل ملكية حصرية (فردية). يتم تحرير الذاكرة تلقائيًا بمجرد الخروج من النطاق. لا يمكن نسخه، بل يُسمح فقط بـ &amp;ldquo;نقل (Move)&amp;rdquo; الملكية (باستخدام &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; // خطأ في وقت الترجمة (النسخ غير مسموح)
&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">// نقل الملكية
&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">// نقطة ضعف C++: بعد النقل، يصبح p1 مساويًا لـ nullptr، ولكن الوصول إليه لا يزال قابلاً للترجمة
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="c1">// سيؤدي ذلك إلى انهيار (Segmentation fault) في وقت التشغيل
&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>مؤشر يسمح لمؤشرات متعددة بمشاركة نفس الكائن. يستخدم عداد المراجع (Reference Counting)، وبمجرد وصول العداد إلى 0، يتم تحرير الذاكرة. يتطلب عمليات زيادة ونقصان ذرية (Atomic)، مما يسبب نفقات إضافية طفيفة في الأداء (تعادل $O_{sync}$ المذكور سابقًا).&lt;/p>
&lt;h2 id="3-الملكية-ownership-في-rust-نقلة-نوعية">3. الملكية (Ownership) في Rust: نقلة نوعية
&lt;/h2>&lt;p>تضع Rust مفهوم &lt;code>std::unique_ptr&lt;/code> الخاص بـ C++ كجوهر لمواصفات اللغة، مع تطبيق &amp;ldquo;نموذج ملكية&amp;rdquo; أكثر صرامة.&lt;/p>
&lt;h3 id="القواعد-الثلاث-للملكية">القواعد الثلاث للملكية
&lt;/h3>&lt;p>يعتمد نظام الملكية في Rust على ثلاث قواعد بسيطة للغاية:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>كل قيمة في Rust تمتلك متغيرًا يُسمى &amp;ldquo;المالك&amp;rdquo; (Owner).&lt;/strong>&lt;/li>
&lt;li>&lt;strong>يمكن أن يكون هناك مالك واحد فقط في أي وقت.&lt;/strong>&lt;/li>
&lt;li>&lt;strong>عندما يخرج المالك من النطاق (Scope)، سيتم تدمير القيمة.&lt;/strong>&lt;/li>
&lt;/ol>
&lt;p>في Rust، يتم &amp;ldquo;نقل&amp;rdquo; الموارد افتراضيًا. تنتقل الملكية عن طريق عملية التعيين دون الحاجة إلى تحديد &lt;code>std::move&lt;/code> صراحة كما في C++.&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: نقل الملكية (Move)
&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">// بيانات مخصصة في الكومة
&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">// تنتقل الملكية من s1 إلى 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">// الفرق الأكبر مع C++: الوصول إلى متغير بعد نقله يؤدي إلى &amp;#34;خطأ في وقت الترجمة&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); // خطأ في الترجمة: 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>ميزة &amp;ldquo;جعل الوصول إلى المتغيرات بعد النقل مستحيلاً في وقت الترجمة&amp;rdquo; هي أحد الأسباب التي تجعل Rust أكثر أمانًا من &lt;code>std::unique_ptr&lt;/code> في C++.&lt;/p>
&lt;div class="mermaid">sequenceDiagram
participant S1 as "المتغير s1"
participant Heap as "ذاكرة الكومة ('hello')"
participant S2 as "المتغير s2"
S1->>Heap: "يخصص ويملك"
Note over S1,S2: "let s2 = s1;"
S1--xHeap: "يفقد الملكية (مُبطل)"
S2->>Heap: "يأخذ الملكية"&lt;/div>
&lt;h2 id="4-الاستعارة-borrowing-والمراجع">4. الاستعارة (Borrowing) والمراجع
&lt;/h2>&lt;p>إذا كانت الملكية تنتقل باستمرار، فسيتعين إرجاع الملكية في كل مرة يتم فيها تمرير قيمة إلى دالة، وهو أمر غير مريح للغاية. وهنا يأتي دور &amp;ldquo;الاستعارة (Borrowing)&amp;rdquo;. وهو يعادل المؤشرات أو المراجع في C++.&lt;/p>
&lt;p>هناك نوعان من الاستعارة في Rust:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>المرجع غير القابل للتغيير (Immutable Reference)&lt;/strong>: &lt;code>&amp;amp;T&lt;/code> (مشابه لـ &lt;code>const T&amp;amp;&lt;/code> في C++)&lt;/li>
&lt;li>&lt;strong>المرجع القابل للتغيير (Mutable Reference)&lt;/strong>: &lt;code>&amp;amp;mut T&lt;/code> (مشابه لـ &lt;code>T&amp;amp;&lt;/code> في C++)&lt;/li>
&lt;/ul>
&lt;h3 id="القانون-الصارم-لمدقق-الاستعارة-borrow-checker">القانون الصارم لمدقق الاستعارة (Borrow Checker)
&lt;/h3>&lt;p>يحتوي مترجم Rust على &amp;ldquo;مدقق الاستعارة&amp;rdquo; الذي يتحقق من صحة المراجع. يفرض مدقق الاستعارة القواعد الصارمة التالية:&lt;/p>
&lt;blockquote>
&lt;p>في أي نطاق معين، يمكن أن يوجد واحد فقط مما يلي:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>مرجع واحد قابل للتغيير (&lt;code>&amp;amp;mut T&lt;/code>)&lt;/strong>&lt;/li>
&lt;li>&lt;strong>عدة مراجع غير قابلة للتغيير (&lt;code>&amp;amp;T&lt;/code>)&lt;/strong>&lt;/li>
&lt;/ul>
&lt;/blockquote>
&lt;p>يُعرف هذا بمبدأ &lt;strong>&amp;ldquo;قراء متعددون أو كاتب واحد (MRSW)&amp;rdquo; (Multiple Readers XOR Single Writer)&lt;/strong>. يمكن التعبير عن ذلك بواسطة المعامل الرياضي (XOR) (الاستبعاد المنطقي). بالنسبة للحالة $S$، يجب أن يفي عدد المراجع غير القابلة للتغيير $N_r$ وعدد المراجع القابلة للتغيير $N_w$ بالشرط التالي:&lt;/p>
$$ (N_r \ge 0 \land N_w = 0) \oplus (N_r = 0 \land N_w = 1) $$
&lt;p>من خلال هذه القاعدة، يتم &lt;strong>منع سباق البيانات (Data Race) تمامًا في وقت الترجمة&lt;/strong>. يحدث سباق البيانات عندما: (1) يصل مؤشران أو أكثر إلى نفس البيانات في وقت واحد، (2) يقوم واحد على الأقل بالكتابة، و (3) لا توجد آلية للمزامنة. تمنع Rust سباق البيانات مسبقًا عن طريق تدمير الشرط (2) في وقت الترجمة.&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: خطأ في وقت الترجمة بسبب انتهاك قواعد الاستعارة
&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">// استعارة غير قابلة للتغيير (موافق)
&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">// استعارة غير قابلة للتغيير (موافق)
&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; // خطأ! لا يمكن إنشاء استعارة قابلة للتغيير بينما توجد استعارة غير قابلة للتغيير
&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-منع-إبطال-المكرر-iterator-invalidation">5. منع إبطال المكرر (Iterator Invalidation)
&lt;/h2>&lt;p>كمثال عملي يبرز قوة مدقق الاستعارة بشكل أفضل، دعونا نلقي نظرة على الخلل الكلاسيكي المعروف باسم &amp;ldquo;إبطال المكرر&amp;rdquo;.&lt;/p>
&lt;h3 id="إبطال-المكرر-في-c-انهيار-وقت-التشغيل">إبطال المكرر في C++ (انهيار وقت التشغيل)
&lt;/h3>&lt;p>عند تعديل &lt;code>std::vector&lt;/code> في C++ داخل حلقة تكرارية، هناك احتمال أن يتم إعادة تخصيص الذاكرة الأساسية (Reallocation)، مما يحول المرجع إلى مؤشر متدلٍ (Dangling Pointer).&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++: خطأ إبطال المكرر
&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">// الحصول على مرجع لعنصر في المتجه
&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">// إضافة عنصر (إذا كانت السعة غير كافية هنا، فسيتم تخصيص مساحة ذاكرة جديدة،
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="c1">// وقد يتم التخلص من المساحة القديمة)
&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 بالفعل إلى ذاكرة تم تحريرها! (سلوك غير محدد)
&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="حماية-وقت-الترجمة-بواسطة-rust">حماية وقت الترجمة بواسطة Rust
&lt;/h3>&lt;p>دعونا نكتب نفس المنطق تمامًا باستخدام 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: منع إبطال المكرر في وقت الترجمة
&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">// الحصول على مرجع غير قابل للتغيير (بدء الاستعارة)
&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">// خطأ! طالما أن `first` يستعير `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">// لا يمكنك إجراء استعارة قابلة للتغيير المطلوبة لـ `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>وبهذه الطريقة، تمنع Rust على مستوى المترجم &amp;ldquo;تعديل القيمة (استعارة قابلة للتغيير) أثناء قراءتها (استعارة غير قابلة للتغيير)&amp;quot;، مما يضمن اكتشاف الأخطاء القاتلة مثل الاستخدام بعد التحرير (Use-After-Free) وإبطال المكرر في وقت الترجمة بشكل مؤكد.&lt;/p>
&lt;div class="mermaid">graph LR
A["المتغير v (المالك)"] --> B["مصفوفة الكومة [1, 2, 3]"]
C["المرجع 'first' (&amp;v[0])"] -.->|"استعارة غير قابلة للتغيير"| B
A -->|X "استعارة قابلة للتغيير مرفوضة!"| D["v.push(4)"]
style C stroke:#00FF00,stroke-width:2px
style D stroke:#FF0000,stroke-width:2px&lt;/div>
&lt;h2 id="6-الملكية-المشتركة-في-rust-rc-و-arc">6. الملكية المشتركة في Rust: &lt;code>Rc&lt;/code> و &lt;code>Arc&lt;/code>
&lt;/h2>&lt;p>توفر Rust أيضًا ملكية مشتركة تعادل &lt;code>std::shared_ptr&lt;/code> في C++، ولكن هناك تمييز واضح في الأنواع للاستخدام في خيط واحد (Single Thread) أو عبر خيوط متعددة (Multi-thread).&lt;/p>
&lt;h3 id="للخيط-الواحد-rct-reference-counted">للخيط الواحد: &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> هو مؤشر ذكي يعتمد على عد المراجع ولكنه ليس آمنًا للخيوط (Non-thread-safe). نظرًا لأنه يزيد أو ينقص العداد دون استخدام تعليمات ذرية، فهو سريع جدًا داخل خيط واحد. ومع ذلك، إذا حاولت إرساله إلى خيط آخر، فسيحدث خطأ في الترجمة (لأنه لا ينفذ سمة &lt;code>Send&lt;/code>).&lt;/p>
&lt;h3 id="للخيوط-المتعددة-arct-atomic-reference-counted">للخيوط المتعددة: &lt;code>Arc&amp;lt;T&amp;gt;&lt;/code> (Atomic Reference Counted)
&lt;/h3>&lt;p>للمشاركة بين الخيوط، يتم استخدام &lt;code>Arc&amp;lt;T&amp;gt;&lt;/code> الذي يقوم بعمليات زيادة ونقصان ذرية (Atomic). تتكبد تكلفة تعادل &lt;code>std::shared_ptr&lt;/code> في C++.&lt;/p>
&lt;p>علاوة على ذلك، في C++، إذا حاولت عدة خيوط الكتابة في نفس الوقت إلى متغير مشترك بواسطة &lt;code>std::shared_ptr&lt;/code>، فسيحدث سباق بيانات. لمنع ذلك، يجب استخدام &lt;code>std::mutex&lt;/code> بشكل صحيح يدويًا.&lt;/p>
&lt;p>من ناحية أخرى في Rust، لا يمكن لـ &lt;code>Arc&amp;lt;T&amp;gt;&lt;/code> &lt;strong>تغيير البيانات الداخلية بمفرده&lt;/strong>. إذا كانت التعديلات ضرورية، يجب دمجه مع كائن مزامنة &lt;code>Mutex&amp;lt;T&amp;gt;&lt;/code>.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-rust" data-lang="rust">&lt;span class="line">&lt;span class="cl">&lt;span class="k">use&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">std&lt;/span>::&lt;span class="n">sync&lt;/span>::&lt;span class="p">{&lt;/span>&lt;span class="n">Arc&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">Mutex&lt;/span>&lt;span class="p">};&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="k">use&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">std&lt;/span>::&lt;span class="n">thread&lt;/span>&lt;span class="p">;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="k">fn&lt;/span> &lt;span class="nf">main&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="c1">// مزيج من المشاركة الآمنة للخيوط والتحكم الحصري
&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">// مشابه لـ std::shared_ptr&amp;lt;std::mutex&amp;gt; في C++، لكن المتيوتكس (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">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">// عن طريق استدعاء lock()، يمكنك الحصول على مرجع قابل للتغيير (&amp;amp;mut i32) داخليًا
&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">// يتم تحرير القفل تلقائيا عند الخروج من النطاق بسبب مبدأ RAII
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">handles&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">push&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">handle&lt;/span>&lt;span class="p">);&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="k">for&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">handle&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="k">in&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="n">handles&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="p">{&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="n">handle&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">join&lt;/span>&lt;span class="p">().&lt;/span>&lt;span class="n">unwrap&lt;/span>&lt;span class="p">();&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="p">}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="fm">println!&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;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>والجدير بالذكر أن &lt;code>Mutex&amp;lt;T&amp;gt;&lt;/code> في Rust ليس مجرد آلية قفل فحسب، بل &lt;strong>&amp;ldquo;يغلف البيانات التي يجب حمايتها كنوع&amp;rdquo;&lt;/strong>. يمنع هذا التصميم بالكامل خطأ &amp;ldquo;الوصول إلى البيانات ونسيان القفل&amp;rdquo; على مستوى الترجمة. النظام مبني بحيث لا يمكنك الحصول على حق الوصول (مرجع) للبيانات الداخلية دون الحصول على القفل أولاً (&lt;code>lock()&lt;/code>).&lt;/p>
&lt;h2 id="الخلاصة-فحص-مسبق-بواسطة-المترجم-أم-مسؤولية-شخصية-للمطور">الخلاصة: &amp;ldquo;فحص مسبق&amp;rdquo; بواسطة المترجم أم &amp;ldquo;مسؤولية شخصية&amp;rdquo; للمطور؟
&lt;/h2>&lt;p>توفر المؤشرات والمؤشرات الذكية في C++ للمطور تحكمًا متقدمًا وأداءً عاليًا، ولكن الاستخدام الصحيح لها يعتمد على انضباط المطور. على الرغم من أن C++ أصبحت أكثر أمانًا بشكل دراماتيكي مع إدخال RAII و &lt;code>std::unique_ptr&lt;/code>، إلا أنها لا تستطيع منع &amp;ldquo;السلوك غير المحدد&amp;rdquo; تمامًا على مستوى اللغة، مثل الوصول بعد النقل أو إبطال المكرر.&lt;/p>
&lt;p>من ناحية أخرى، من خلال تضمين قواعد الملكية (Ownership) والاستعارة (Borrowing) في المترجم، تكتشف Rust هذه الأخطاء &lt;strong>في وقت الترجمة&lt;/strong> بدلاً من وقت التشغيل. إن الضمان القوي المتمثل في &amp;ldquo;إذا نجحت عملية الترجمة، فإن الذاكرة آمنة&amp;rdquo; هو السبب الأكبر الذي جعل Rust تكتسب دعمًا سريعًا في برمجة الأنظمة.&lt;/p>
&lt;p>على الرغم من أن القتال ضد مدقق الاستعارة في Rust (Fight the borrow checker) يمثل عقبة كبيرة للمبتدئين، إلا أنه في الواقع قيام المترجم بالنيابة عنك بعملية حسابية معقدة تتمثل في &amp;ldquo;تتبع مدة بقاء المؤشر&amp;rdquo;، والتي كان مبرمجو C++ يقومون بها عادة في رؤوسهم.&lt;/p>
&lt;p>إذا تعلمت Rust بعد فهم حرية ومخاطر مؤشرات C++، فيجب أن تكون قادرًا على فهم أعمق للفلسفة الكامنة وراء نموذج الملكية و&amp;quot;لماذا تم اعتماده بهذا التصميم&amp;rdquo;.&lt;/p>
&lt;hr>
&lt;p>&lt;em>هذه المقالة هي دراسة مقارنة حول طرق إدارة الذاكرة في C++ و Rust. نأمل أن تكون بمثابة مرجع لاختيار اللغة المناسبة وفقًا لمتطلبات كل مشروع.&lt;/em>&lt;/p></description></item></channel></rss>