<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Smart Pointers on kenji.blog</title><link>http://kenji.blog/ar/tags/smart-pointers/</link><description>Recent content in Smart Pointers on kenji.blog</description><generator>Hugo -- gohugo.io</generator><language>ar</language><copyright>kenjinote</copyright><lastBuildDate>Sat, 12 Sep 2026 07:00:00 +0900</lastBuildDate><atom:link href="http://kenji.blog/ar/tags/smart-pointers/index.xml" rel="self" type="application/rss+xml"/><item><title>استراتيجيات استخدام المؤشرات الذكية (std::unique_ptr / shared_ptr) لمنع تسرب الذاكرة</title><link>http://kenji.blog/ar/p/cpp-smart-pointers-guide-unique-shared-ptr/</link><pubDate>Sat, 12 Sep 2026 07:00:00 +0900</pubDate><guid>http://kenji.blog/ar/p/cpp-smart-pointers-guide-unique-shared-ptr/</guid><description>&lt;img src="http://kenji.blog/p/cpp-smart-pointers-guide-unique-shared-ptr/img/eyecatch.jpg" alt="Featured image of post استراتيجيات استخدام المؤشرات الذكية (std::unique_ptr / shared_ptr) لمنع تسرب الذاكرة" />&lt;p>لطالما كانت إدارة الذاكرة في لغة C++ إحدى أكبر التحديات التي تواجه المطورين لسنوات طويلة. كان أسلوب إدارة الذاكرة التقليدي الذي يعتمد على الاستخدام اليدوي لـ &lt;code>new&lt;/code> و &lt;code>delete&lt;/code> بيئة خصبة لأخطاء برمجية خطيرة مثل تسرب الذاكرة (Memory Leaks)، والمؤشرات المعلقة (Dangling Pointers)، والتحرير المزدوج للذاكرة (Double Free). ولكن مع ظهور C++ الحديثة (Modern C++) بدءاً من معيار C++11، تغير الوضع بشكل جذري. ويكمن جوهر هذا التغيير في &amp;ldquo;المؤشرات الذكية&amp;rdquo; (Smart Pointers).&lt;/p>
&lt;p>في هذا المقال، سنشرح بتفصيل شديد آليات عمل &lt;code>std::unique_ptr&lt;/code> و &lt;code>std::shared_ptr&lt;/code> و &lt;code>std::weak_ptr&lt;/code>، والتي تُعد أدوات قوية للقضاء على تسرب الذاكرة وتحقيق إدارة آمنة وفعالة للموارد. سنتناول استراتيجيات الاستخدام المتقدمة، مع التطرق إلى التطبيق الداخلي (مثل كتلة التحكم والعمليات الذرية)، وتأثيرها على الأداء، والصياغة الرياضية لعد المراجع (Reference Counting).&lt;/p>
&lt;h2 id="1-مقدمة-العصر-المظلم-لإدارة-الذاكرة-في-c-وفجر-modern-c">1. مقدمة: العصر المظلم لإدارة الذاكرة في C++ وفجر Modern C++
&lt;/h2>&lt;p>في تطوير C++ قديماً، كان المطور مسؤولاً بشكل مباشر عن تحرير الذاكرة المخصصة على الكومة (Heap).&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;span class="lnt">7
&lt;/span>&lt;span class="lnt">8
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="kt">void&lt;/span> &lt;span class="nf">legacy_function&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">int&lt;/span>&lt;span class="o">*&lt;/span> &lt;span class="n">ptr&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">new&lt;/span> &lt;span class="kt">int&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">10&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// ... بعض العمليات ...
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">some_condition&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="c1">// حدوث تسرب للذاكرة! لم يتم استدعاء delete
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">delete&lt;/span> &lt;span class="n">ptr&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>في كود مثل الموضح أعلاه، عند حدوث استثناء (Exception) أو الإرجاع المبكر (Early Return)، يتم تخطي استدعاء &lt;code>delete&lt;/code> مما يؤدي إلى تسرب الذاكرة. ولمنع ذلك، ظهر نموذج &amp;ldquo;RAII&amp;rdquo; (Resource Acquisition Is Initialization). RAII هو أسلوب يربط بين حجز الموارد وتهيئة الكائن (في دالة البناء)، وتحرير الموارد وتدمير الكائن (في دالة الهدم). المؤشرات الذكية هي فئات في المكتبة القياسية تُطبق نمط RAII هذا على إدارة الذاكرة.&lt;/p>
&lt;h2 id="2-stdunique_ptr-ملكية-حصرية-بدون-تكلفة-إضافية-zero-overhead">2. &lt;code>std::unique_ptr&lt;/code>: ملكية حصرية بدون تكلفة إضافية (Zero-Overhead)
&lt;/h2>&lt;p>&lt;code>std::unique_ptr&lt;/code> هو مؤشر ذكي يمتلك &amp;ldquo;ملكية حصرية&amp;rdquo; (Exclusive Ownership) للكائن المخصص ديناميكيًا. يمكن لمؤشر &lt;code>unique_ptr&lt;/code> واحد فقط أن يمتلك مورداً معيناً في أي وقت.&lt;/p>
&lt;h3 id="21-مبدأ-التكلفة-الصفرية-zero-overhead-principle">2.1 مبدأ التكلفة الصفرية (Zero-Overhead Principle)
&lt;/h3>&lt;p>الميزة الأكبر لـ &lt;code>std::unique_ptr&lt;/code> هي أداؤه. في حالته الافتراضية وبدون وجود حاذف مخصص (Custom Deleter)، يكون حجم &lt;code>std::unique_ptr&lt;/code> مطابقاً تماماً لحجم المؤشر الخام (Raw Pointer). فهو لا يحتوي على أي متغيرات أعضاء غير ضرورية، ولا يستخدم دوال افتراضية (Virtual Functions). بفضل تحسينات المترجم (Compiler Optimization)، يتم تحويل الوصول عبر &lt;code>std::unique_ptr&lt;/code> إلى كود تجميع (Assembly) مكافئ تماماً لاستخدام المؤشر الخام.&lt;/p>
&lt;h3 id="22-نقل-الملكية-و-stdmove">2.2 نقل الملكية و &lt;code>std::move&lt;/code>
&lt;/h3>&lt;p>نظرًا لامتلاكه ملكية حصرية، لا يمكن نسخ &lt;code>std::unique_ptr&lt;/code> (تم حذف دالة البناء بالنسخ ومعامل التعيين بالنسخ باستخدام &lt;code>delete&lt;/code>). لنقل الملكية إلى &lt;code>unique_ptr&lt;/code> آخر، نستخدم &lt;code>std::move&lt;/code> للاستفادة من دلالات النقل (Move Semantics).&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;iostream&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;memory&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">Resource&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">public&lt;/span>&lt;span class="o">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">Resource&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;Resource acquired&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s">&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">~&lt;/span>&lt;span class="n">Resource&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;Resource destroyed&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s">&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">void&lt;/span> &lt;span class="nf">do_something&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;Doing something&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s">&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">};&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kt">void&lt;/span> &lt;span class="nf">process_resource&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">unique_ptr&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">Resource&lt;/span>&lt;span class="o">&amp;gt;&lt;/span> &lt;span class="n">ptr&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">ptr&lt;/span>&lt;span class="o">-&amp;gt;&lt;/span>&lt;span class="n">do_something&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// عند الخروج من النطاق (Scope)، يتم تدمير ptr وتحرير Resource
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kt">int&lt;/span> &lt;span class="nf">main&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">unique_ptr&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">Resource&lt;/span>&lt;span class="o">&amp;gt;&lt;/span> &lt;span class="n">my_ptr&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">make_unique&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">Resource&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// process_resource(my_ptr); // خطأ: لا يمكن النسخ
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">process_resource&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">move&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">my_ptr&lt;/span>&lt;span class="p">));&lt;/span> &lt;span class="c1">// نقل الملكية
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="o">!&lt;/span>&lt;span class="n">my_ptr&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;my_ptr is now empty.&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s">&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>يوضح مخطط Mermaid التالي مفهوم نقل الملكية باستخدام &lt;code>std::move&lt;/code>.&lt;/p>
&lt;div class="mermaid">graph LR
subgraph "قبل std::move"
A["unique_ptr (ptr1)"] -->|"يمتلك"| B["ذاكرة الكومة (كائن)"]
end
subgraph "بعد std::move"
C["unique_ptr (ptr1)"] -.->|"فارغ (nullptr)"| D["nullptr"]
E["unique_ptr (ptr2)"] -->|"يمتلك"| F["ذاكرة الكومة (كائن)"]
end&lt;/div>
&lt;h3 id="23-تنفيذ-حاذف-مخصص-custom-deleter">2.3 تنفيذ حاذف مخصص (Custom Deleter)
&lt;/h3>&lt;p>عند تغليف واجهات برمجة التطبيقات القديمة (Legacy APIs) الخاصة بلغة C (مثل &lt;code>FILE*&lt;/code> أو مآخذ التوصيل Sockets)، نحتاج إلى استدعاء دالة غير &lt;code>delete&lt;/code> (مثل &lt;code>fclose&lt;/code>) لتحرير الذاكرة. يتيح &lt;code>std::unique_ptr&lt;/code> تحديد حاذف مخصص كمعلمة قالب ثانية (Template Parameter).&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;cstdio&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;memory&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// كائن دالي (Functor) للحاذف المخصص
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="k">struct&lt;/span> &lt;span class="nc">FileDeleter&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">void&lt;/span> &lt;span class="nf">operator&lt;/span>&lt;span class="p">()(&lt;/span>&lt;span class="n">FILE&lt;/span>&lt;span class="o">*&lt;/span> &lt;span class="n">fp&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">const&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">fp&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;Closing file.&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s">&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">fclose&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">fp&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">};&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">using&lt;/span> &lt;span class="n">UniqueFile&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">unique_ptr&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">FILE&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">FileDeleter&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kt">int&lt;/span> &lt;span class="nf">main&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">UniqueFile&lt;/span> &lt;span class="n">file&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">fopen&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;test.txt&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s">&amp;#34;w&amp;#34;&lt;/span>&lt;span class="p">));&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">file&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">fputs&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;Hello, Smart Pointers!&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">file&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="p">());&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// عند انتهاء النطاق، يتم استدعاء FileDeleter وبالتالي fclose
&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>إذا استخدمنا مؤشر دالة أو تعبير لامبدا (Lambda) كحاذف مخصص، فقد يزداد حجم &lt;code>unique_ptr&lt;/code>، ولكن استخدام كائن دالي عديم الحالة (Stateless Functor) كما هو موضح أعلاه يحافظ على الحجم ليكون مساويًا للمؤشر الخام بفضل &lt;strong>EBCO (Empty Base Class Optimization)&lt;/strong> في C++ أو السمة &lt;code>[[no_unique_address]]&lt;/code> في C++20 (مما يحافظ على التكلفة الصفرية).&lt;/p>
&lt;h2 id="3-stdshared_ptr-الملكية-المشتركة-وكتلة-التحكم">3. &lt;code>std::shared_ptr&lt;/code>: الملكية المشتركة وكتلة التحكم
&lt;/h2>&lt;p>&lt;code>std::shared_ptr&lt;/code> هو مؤشر ذكي يسمح لعدة مؤشرات بمشاركة ملكية نفس الكائن. يتم تحرير الكائن المُدار فقط عندما يتم تدمير آخر &lt;code>shared_ptr&lt;/code> يشير إليه.&lt;/p>
&lt;h3 id="31-البنية-الداخلية-كتلة-التحكم-control-block">3.1 البنية الداخلية: كتلة التحكم (Control Block)
&lt;/h3>&lt;p>بالإضافة إلى المؤشر الذي يشير إلى الكائن المُدار، يخصص &lt;code>std::shared_ptr&lt;/code> بيانات وصفية (Metadata) تسمى &lt;strong>كتلة التحكم (Control Block)&lt;/strong> على الكومة لمشاركتها. تتضمن كتلة التحكم المعلومات التالية:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>العد القوي (Strong Count)&lt;/strong>: عدد مؤشرات &lt;code>shared_ptr&lt;/code> التي تمتلك الكائن. عندما يصبح هذا العدد 0، يتم تدمير الكائن.&lt;/li>
&lt;li>&lt;strong>العد الضعيف (Weak Count)&lt;/strong>: عدد مؤشرات &lt;code>weak_ptr&lt;/code> التي تراقب الكائن. عندما يصبح كل من العد القوي والعد الضعيف 0، يتم تحرير كتلة التحكم نفسها.&lt;/li>
&lt;li>&lt;strong>الحاذف المخصص والمُخصص (Custom Deleter &amp;amp; Allocator)&lt;/strong> (إذا تم تحديدهما).&lt;/li>
&lt;/ol>
&lt;div class="mermaid">graph TD
A["std::shared_ptr&lt;T> (sp1)"] -->|"مؤشر إلى T"| B["الكائن المُدار (T)"]
A -->|"مؤشر إلى كتلة التحكم"| C["كتلة التحكم"]
D["std::shared_ptr&lt;T> (sp2)"] -->|"مؤشر إلى T"| B
D -->|"مؤشر إلى كتلة التحكم"| C
C -->|"يحذف"| B
C -.->|"العد القوي: 2"| E["العد القوي"]
C -.->|"العد الضعيف: 0"| F["العد الضعيف"]
C -.->|"حاذف مخصص"| G["الحاذف"]&lt;/div>
&lt;p>لهذا السبب، يكون حجم الكائن &lt;code>std::shared_ptr&lt;/code> نفسه عادةً ضعف حجم المؤشر الخام (مؤشر للكائن المُدار، ومؤشر لكتلة التحكم).&lt;/p>
&lt;h3 id="32-الأداء-والعمليات-الذرية-atomic-operations">3.2 الأداء والعمليات الذرية (Atomic Operations)
&lt;/h3>&lt;p>يتم تنفيذ عداد المراجع داخل كتلة التحكم كـ &lt;strong>عمليات ذرية (Atomic Operations)&lt;/strong> لضمان زيادته ونقصانه بأمان في البيئات متعددة الخيوط (Multithreaded).&lt;/p>
&lt;p>في معمارية x86/x64، تُستخدم تعليمات ذرية مثل &lt;code>lock xadd&lt;/code> لزيادة أو إنقاص عداد المراجع. يصاحب ذلك تكلفة إضافية (Overhead) تبلغ عشرات دورات المعالج مقارنة بجمع الأعداد الصحيحة العادية. وبالتالي، فإن تمرير &lt;code>shared_ptr&lt;/code> بالقيم (Pass by Value) إلى دالة سيؤدي إلى زيادة ونقصان ذري في كل عملية نسخ، مما يؤدي إلى تدهور الأداء.&lt;/p>
&lt;p>&lt;strong>أفضل الممارسات&lt;/strong>: عند تمرير &lt;code>shared_ptr&lt;/code> إلى دالة، ما لم تكن هناك حاجة لمشاركة الملكية، يجب تمريره كمرجع ثابت &lt;code>const std::shared_ptr&amp;lt;T&amp;gt;&amp;amp;&lt;/code>، أو تمرير المؤشر الخام/المرجع بدلاً من ذلك.&lt;/p>
&lt;h3 id="33-stdmake_shared-مقابل-new">3.3 &lt;code>std::make_shared&lt;/code> مقابل &lt;code>new&lt;/code>
&lt;/h3>&lt;p>عند إنشاء &lt;code>shared_ptr&lt;/code>، يجب استخدام &lt;code>std::make_shared&lt;/code> قدر الإمكان. هناك سببان مهمان لذلك:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>تحسين تخصيص الذاكرة&lt;/strong>:
عند استخدام &lt;code>new&lt;/code>، يتم إجراء تخصيصين للذاكرة على الكومة: تخصيص للكائن نفسه وتخصيص لكتلة التحكم. بينما يتيح &lt;code>std::make_shared&lt;/code> تخصيص كتلة ذاكرة واحدة كبيرة تشمل كليهما في عملية تخصيص واحدة، مما يحسن كفاءة الذاكرة المخبئية (Cache).&lt;/li>
&lt;li>&lt;strong>أمان الاستثناءات (Exception Safety)&lt;/strong>:
في معايير C++ قبل C++17، لم يكن ترتيب تقييم وسائط الدالة محددًا، لذا إذا تم تخصيص مؤشر باستخدام &lt;code>new&lt;/code> وحدث استثناء أثناء تقييم وسائط أخرى قبل تمريره إلى دالة بناء &lt;code>shared_ptr&lt;/code>، كان هناك خطر تسرب الذاكرة. أداة &lt;code>make_shared&lt;/code> تتجنب هذه المشكلة تماماً.&lt;/li>
&lt;/ol>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// الطريقة التي يجب تجنبها (تخصيص الذاكرة مرتين)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">shared_ptr&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">MyClass&lt;/span>&lt;span class="o">&amp;gt;&lt;/span> &lt;span class="n">ptr1&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="k">new&lt;/span> &lt;span class="n">MyClass&lt;/span>&lt;span class="p">());&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// الطريقة الموصى بها (تخصيص الذاكرة مرة واحدة)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">shared_ptr&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">MyClass&lt;/span>&lt;span class="o">&amp;gt;&lt;/span> &lt;span class="n">ptr2&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">make_shared&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">MyClass&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h2 id="4-stdweak_ptr-حل-مشكلة-المراجع-الدائرية-والمراقبة">4. &lt;code>std::weak_ptr&lt;/code>: حل مشكلة المراجع الدائرية والمراقبة
&lt;/h2>&lt;p>تحتوي الملكية المشتركة على نقطة ضعف قاتلة تُعرف باسم &amp;ldquo;المراجع الدائرية&amp;rdquo; (Circular References). إذا كان الكائن A والكائن B يشيران إلى بعضهما البعض باستخدام &lt;code>shared_ptr&lt;/code>، فسيظل العد القوي لكل منهما 1 على الأقل، ولن يصبح 0 أبدًا حتى ينتهي البرنامج، مما يؤدي إلى تسرب الذاكرة.&lt;/p>
&lt;div class="mermaid">graph TD
subgraph "مرجع دائري (تسرب الذاكرة)"
A["الكائن A"] -->|"shared_ptr (Strong=1)"| B["الكائن B"]
B -->|"shared_ptr (Strong=1)"| A
end&lt;/div>
&lt;h3 id="41-كسر-الدائرة-بواسطة-stdweak_ptr">4.1 كسر الدائرة بواسطة &lt;code>std::weak_ptr&lt;/code>
&lt;/h3>&lt;p>التي تحل هذه المشكلة هي &lt;code>std::weak_ptr&lt;/code>. يتم إنشاء &lt;code>weak_ptr&lt;/code> من &lt;code>shared_ptr&lt;/code> ويشير إلى الكائن، ولكنه &lt;strong>لا يزيد من العد القوي&lt;/strong>. بدلاً من ذلك، يزيد من العد الضعيف. يتيح هذا &amp;ldquo;مراقبة&amp;rdquo; الكائن دون امتلاكه.&lt;/p>
&lt;div class="mermaid">graph TD
subgraph "كسر المرجع الدائري"
C["الكائن A"] -->|"shared_ptr (Strong=1)"| D["الكائن B"]
D -.->|"weak_ptr (Weak=1)"| C
end&lt;/div>
&lt;h3 id="42-الوصول-الآمن-عبر-التابع-lock">4.2 الوصول الآمن عبر التابع &lt;code>lock()&lt;/code>
&lt;/h3>&lt;p>لا يمتلك &lt;code>weak_ptr&lt;/code> عوامل تشغيل للوصول المباشر إلى الكائن (مثل &lt;code>-&amp;gt;&lt;/code> أو &lt;code>*&lt;/code>). ويرجع ذلك إلى احتمال أن يكون الكائن المستهدف قد تم تدميره بالفعل. للوصول بأمان، نقوم باستدعاء التابع &lt;code>lock()&lt;/code> للحصول مؤقتاً على &lt;code>shared_ptr&lt;/code>.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;iostream&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;memory&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">Node&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">public&lt;/span>&lt;span class="o">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">string&lt;/span> &lt;span class="n">name&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">shared_ptr&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">Node&lt;/span>&lt;span class="o">&amp;gt;&lt;/span> &lt;span class="n">next&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">weak_ptr&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">Node&lt;/span>&lt;span class="o">&amp;gt;&lt;/span> &lt;span class="n">prev&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="c1">// استخدام weak_ptr لمنع المرجع الدائري
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">Node&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="k">const&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">string&lt;/span>&lt;span class="o">&amp;amp;&lt;/span> &lt;span class="n">n&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">:&lt;/span> &lt;span class="n">name&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">n&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;Created &amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">name&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s">&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">~&lt;/span>&lt;span class="n">Node&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;Destroyed &amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">name&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s">&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">};&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kt">int&lt;/span> &lt;span class="nf">main&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">auto&lt;/span> &lt;span class="n">nodeA&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">make_shared&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">Node&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;A&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">auto&lt;/span> &lt;span class="n">nodeB&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">make_shared&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">Node&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;B&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">nodeA&lt;/span>&lt;span class="o">-&amp;gt;&lt;/span>&lt;span class="n">next&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">nodeB&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">nodeB&lt;/span>&lt;span class="o">-&amp;gt;&lt;/span>&lt;span class="n">prev&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">nodeA&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// الحصول على shared_ptr من weak_ptr للوصول
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="k">auto&lt;/span> &lt;span class="n">locked_prev&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">nodeB&lt;/span>&lt;span class="o">-&amp;gt;&lt;/span>&lt;span class="n">prev&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">lock&lt;/span>&lt;span class="p">())&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;Node B&amp;#39;s prev is &amp;#34;&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="n">locked_prev&lt;/span>&lt;span class="o">-&amp;gt;&lt;/span>&lt;span class="n">name&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s">&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span> &lt;span class="k">else&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">cout&lt;/span> &lt;span class="o">&amp;lt;&amp;lt;&lt;/span> &lt;span class="s">&amp;#34;Node B&amp;#39;s prev is already destroyed.&lt;/span>&lt;span class="se">\n&lt;/span>&lt;span class="s">&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="c1">// يتم تدمير nodeA و nodeB بشكل صحيح
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h2 id="5-قيود-الملكية-المشتركة-في-البيئات-متعددة-الخيوط">5. قيود الملكية المشتركة في البيئات متعددة الخيوط
&lt;/h2>&lt;p>غالبًا ما يُساء فهم أمان الخيوط (Thread Safety) الخاص بـ &lt;code>shared_ptr&lt;/code>. &amp;ldquo;تحديث عداد المراجع داخل كتلة التحكم يعتبر آمنًا للخيوط&amp;rdquo;، ولكن &amp;ldquo;القراءة والكتابة لنفس الكائن &lt;code>shared_ptr&lt;/code> بحد ذاته ليست آمنة للخيوط&amp;rdquo;.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>العمليات الآمنة&lt;/strong>: عدة خيوط تقوم كل منها بقراءة وكتابة &lt;em>نسختها الخاصة&lt;/em> من &lt;code>shared_ptr&lt;/code> (على الرغم من أنها تشترك في نفس كتلة التحكم).&lt;/li>
&lt;li>&lt;strong>سباق البيانات (خطير)&lt;/strong>: عدة خيوط تقوم في وقت واحد بالقراءة والكتابة &lt;em>لنفس الكائن&lt;/em> &lt;code>shared_ptr&lt;/code> بالظبط.&lt;/li>
&lt;/ul>
&lt;p>إذا كانت هناك حاجة لمشاركة نفس النسخة عبر خيوط متعددة، يجب استخدام &lt;code>std::atomic&amp;lt;std::shared_ptr&amp;lt;T&amp;gt;&amp;gt;&lt;/code> (في C++20) أو حمايته باستخدام كائن قفل (Mutex) &lt;code>std::mutex&lt;/code>.&lt;/p>
&lt;h2 id="6-الصياغة-الرياضية-لعداد-المراجع">6. الصياغة الرياضية لعداد المراجع
&lt;/h2>&lt;p>يمكن التعبير رياضياً عن انتقال حالة دورة الحياة في كتلة التحكم على النحو التالي.
بفرض أن العد القوي في الوقت $t$ هو $S(t)$، والعد الضعيف هو $W(t)$.&lt;/p>
&lt;p>الحالة الأولية (مباشرة بعد &lt;code>make_shared&lt;/code>):
&lt;/p>
$$ S(0) = 1, \quad W(0) = 0 $$
&lt;p>عند حدوث عملية نسخ (تكرار لـ &lt;code>shared_ptr&lt;/code>):
&lt;/p>
$$ S(t_{next}) = S(t) + 1 $$
&lt;p>شرط تدمير الكائن المُدار (Managed Object):
&lt;/p>
$$ \lim_{t \to t_d} S(t) = 0 $$
&lt;p>شرط تحرير كتلة التحكم (Control Block) نفسها من الذاكرة:
&lt;/p>
$$ S(t) = 0 \quad \land \quad W(t) = 0 $$
&lt;p>
أي بمعنى آخر،
&lt;/p>
$$ S(t) + W(t) = 0 $$
&lt;p>كما توضح هذه المعادلات، طالما أن &lt;code>weak_ptr&lt;/code> مستمر في الوجود ($W(t) > 0$)، فستظل مساحة الذاكرة الصغيرة المخصصة لكتلة التحكم محجوزة حتى لو تم تدمير الكائن المُدار. في بعض الحالات، يُعتبر هذا هو العيب الوحيد لـ &lt;code>make_shared&lt;/code> (نظراً لدمج ذاكرة الكائن المُدار مع كتلة التحكم، إذا بقي مرجع ضعيف، فإن مساحة الذاكرة الكبيرة المخصصة للكائن المُدار لن تُعاد إلى النظام). ولكن في العادة، تفوق الفوائد المتعلقة بالأداء لـ &lt;code>make_shared&lt;/code> هذا العيب بكثير.&lt;/p>
&lt;h2 id="7-الخاتمة">7. الخاتمة
&lt;/h2>&lt;p>لم تعد إدارة الذاكرة في C++ الحديثة تتطلب التعامل اليدوي باستخدام &lt;code>new&lt;/code>/&lt;code>delete&lt;/code>.&lt;/p>
&lt;ol>
&lt;li>بشكل افتراضي، استخدم دائمًا &lt;strong>&lt;code>std::unique_ptr&lt;/code>&lt;/strong> لدمج الملكية الواضحة في تصميمك مع الاستفادة من ميزة التكلفة الصفرية.&lt;/li>
&lt;li>استخدم &lt;strong>&lt;code>std::shared_ptr&lt;/code>&lt;/strong> فقط عندما تحتاج حقًا إلى مشاركة دورة الحياة بين عدة مالكين، واستخدم &lt;code>std::make_shared&lt;/code> للإنشاء.&lt;/li>
&lt;li>استخدم &lt;strong>&lt;code>std::weak_ptr&lt;/code>&lt;/strong> في هياكل البيانات التي قد تسبب حلقات (مراجع دائرية) أو في تنفيذ نمط المراقب (Observer Pattern) لمنع تسرب الذاكرة بشكل استباقي.&lt;/li>
&lt;/ol>
&lt;p>من خلال الفهم العميق للمؤشرات الذكية واستخدامها في المكان المناسب، يصبح من الممكن بناء بنية برمجية آمنة وقوية دون التضحية بأي شيء من أداء C++.&lt;/p></description></item></channel></rss>