• الإعلانات

    • فيصل الحربي

      تسجيل عضوية جديدة في المنتدى   01/31/2016

      السلام عليكم ورحمة الله وبركاته  عزيزي العضو الجديد :  حاليا رسالة الإيميل لتأكيد صحة إيميلكم تذهب للبريد العشوائي ( جاري حل المشكلة )  فإذا لم تجد رسالة التحقق من إيميلكم في صندوق الوارد لديكم إتجه للبريد العشوائي ( JUNK)  وقم بتفعيل إشتراككم من هناك   

Abboodd

الاعضاء المجتهدين
  • عدد المشاركات

    772
  • تاريخ الانضمام

  • تاريخ اخر زياره

السمعه بالموقع

61 جيد

عن Abboodd

  • الرتبة
    عضو مميز
  • تاريخ الميلاد 05/09/1993

طرق الإتصال

  • ICQ 0

معلومات الملف الشخصي

  • الجنس ذكر
  • الدولة : سوريا، حالياً في بيروت...
  • اهتمامات الرياضيات... الكمبيوتر... علم النفس

أحدث الزائرين لملفلك الشخصي

13,144 زياره للملف الشخصي
  1. شكراً لك لم أكن أعرف اسمها :)
  2. الكود يعمل بشكل ممتاز على VC++ 2010... لا يظهر الـdestructor بوضوح على كل حال لذلك أضف endl بعده
  3. شكراً لك أخي الموضوع رائع جداً ومفيد، اسمح لي بأن أضيف شيئاً:   هناك فائدة أخرى رائعة للـpolymorphism وهي إمكانية اختيار النوع المراد استخدامه في وقت التنفيذ... ما المقصود من ذلك؟ المقصود... لنقل أننا نبرمج لعبة شبيهة بنمط Red Alert. فهناك عدة أنواع للجنود، الجندي العادي والطيار وحامل المدفع....   يمكننا عند إنشاء جندي عمل ما يلي:   Soldier* S;switch(choise){case NORMAL: S= new S_Normal;case ROCKETEER: S= new S_Rocketeer;case YURI: S= new S_Yuri;//So on so forth...}  يمكن فيما بعد ببساطة كتابة:   S->Create();...S->Move(//Some location);...S->Attack(//Some enemy);  وسيتم تنفيذ التعليمات الخاصة بالنوع الذي تم اختياره سابقاً.   أكرر شكري لك على هذه الموضوع الرائع :)
  4. المؤشرات الذكية... نظرة أوسع

    المؤشر التلقائي Auto Pointer: كما ذكرت في المرة السابقة، هناك أنواع متعددة للمؤشرات الذكية، لكل منها وظيفة محددة نستعمله من أجلها، ولتكون بدايتنا مريحة، سنبدأ بأبسط أنواع المؤشرات الذكية، وهو المؤشر التلقائي auto_ptr. السؤال الأول الذي يتبادر إلى الذهن.... لماذا تلقائي؟ لأنه ببساطة، يقوم بشكل تلقائي، بتحرير الذاكرة عندما ينتهي عمله، وبالتالي لن تحتاج إلى القلق من مشاكل تسرب الذاكرة –في الحالات البسيطة- عند استعمال هذا المؤشر. مثال بسيط على الأمر، لنفترض أن لدينا الدالة التالية:     void testing(){                int* p= new int;                               //Some code                delete p;}    يبدو هذا الكود آمناً، لكن ماذا يجري إذا خرجت الدالة testing قبل وصولها إلى السطر الأخير؟ ربما تم رمي استثناء أو صادفت جملة return على الطريق... وبالتالي فإن الذاكرة التي حجزها p لن تحرر مما سيؤدي إلى تسرب في الذاكرة. الآن، سيرتدي المؤشر درعه الأول الأنسب لمهمة بسيطة كهذه، درع "التحرير التلقائي"، والرائع في هذا "الدرع" أنه معرف مسبقاً في مكتبة memory القياسية، وبالتالي لا داعي للجوء إلى مصادر خارجية للحصول عليه. الكود التالي يوضح استخدامه:     #include <memory>using namespace std;void testing(){       auto_ptr<int> p(new int);       //Some code}    إذاً، فإن الـauto_ptr هو عبارة عن template class نحدد له في الـtemplate parameter نوع البيانات التي نريد الإشارة إليها بالمؤشر. وهو ككائن عادي، يستدعى الـdestructor الخاص به بشكل تلقائي عند الخروج من الدالة بأي طريقة، حيث يقوم هذا الـdestructor بتحرير الذاكرة بالشكل المناسب. إذاً، فلم يعد هناك خوف من ألا نصل إلى جملة delete، لأن الـdestructor الخاص بالـauto_ptr هو من يستدعيها ولا مفر من الوصول إليه عند انتهاء الدالة. الجميل أيضاً في هذا المؤشر الذكي، أنه من الممكن استعمال معاملات المؤشرات العادية عليه كمعامل الـ* ومعامل <-، مثلاً:     #include <iostream>#include <memory>using namespace std;void testing();class SomeClass{public:       void SomeMethod()       {              cout<< "Wow!! It's working!!\n";       }};int main(){       testing();       return 0;}void testing(){       auto_ptr<int> p1(new int);       *p1= 5;       cout<< *p1<< endl;       auto_ptr<SomeClass> p2(new SomeClass);       p2->SomeMethod();}    هناك خصائص عديدة أخرى يتميز بها المؤشر التلقائي، سنشرحها من خلال صنع مؤشر تلقائي خاص بنا، ولنسمه، AT_auto_ptr.     template <class T>class AT_auto_ptr{private:       T* raw_ptr;public:AT_auto_ptr(): raw_ptr(0) {}       AT_auto_ptr(T* ptr): raw_ptr(ptr) {}       ~AT_auto_ptr()       {              delete raw_ptr;       }};    كما ذكرنا من قبل، فإن المؤشر الذكي هو "درع" أو "غلاف" يخبئ في داخله المؤشر العادي، وبالتالي فإن أهم عنصر في هذا المؤشر الذكي هو المؤشر العادي الذي سيقوم بعملية الإشارة الحقيقية إلى الذاكرة، والذي سميناه هنا raw_ptr. ما يفعله هذا الكلاس هنا ببساطة هو إعطاء قيمة للمؤشر بداخله عند إنشائه، وتحرير الذاكرة عند تدميره. تجدر الإشارة هنا إلى أن المؤشر التلقائي يجب ألّا يشير إلّا إلى ذاكرة في الـheap، أي تم حجزها بشكل ديناميكي باستخدام new وما شابهها. لأنه في حال حاول الإشارة إلى ذاكرة في الـstack فإنه لن يكون قادراً على تحريرها عند استدعاء الـdestructor. إلا إن كانت هناك طريقة لمعرفة إن كانت الذاكرة المشار إليها تابعة للـstack أو الـheap، فعندها ليجاوبنا من عنده علم بذلك  :)    سنقوم الآن بتزويد الكلاس بمعاملات المؤشرات الأساسية:     template <class T>class AT_auto_ptr{private:       T* raw_ptr;public:       AT_auto_ptr(): raw_ptr(0) {}       AT_auto_ptr(T* ptr): raw_ptr(ptr) {}       ~AT_auto_ptr()       {              delete raw_ptr;       }       T& operator * () const       {              return *raw_ptr;       }       T* operator -> () const       {              return raw_ptr;       }};  لاحظ أن الـreturn type الخاص بالمعامل * هو من النوع T& وليس T وذلك لتجنب القيام بعملية نسخ زائدة ليس منها فائدة.   سؤال جوهري يجب طرحه الآن، ماذا يحدث عندما نحاول نسخ مؤشر تلقائي إلى مؤشر تلقائي آخر؟ هذا بالطبع يعتمد على تصميمنا، لكن التصميم المتفق عليه يجعل المؤشر التلقائي يقوم عند نسخه بعملية transfer-of-ownership أو نقل الملكية، حيث يتخلى المؤشر الأصلي عن ملكيته لموقع الذاكرة، ويعطيه للمؤشر الجديد، بينما يسند قيمة مؤشره الداخلي إلى NULL.... يا له من محب للإيثار!! هذه العملية تحمينا من أن يكون هناك أكثر من مؤشر واحد يشير لنفس الموقع في الذاكرة، كما أنها مفيدة عند إرجاع مؤشر من دالة معينة، حيث يمكننا أن نقوم بـ:   auto_ptr<int> testing(){ auto_ptr<int> temp(new int); *temp= 5; return temp;}حيث قامت عملية نقل الملكية بنقل موقع الذاكرة الذي تم حجزه داخل الدالة إلى المؤشر الذي سيلتقط القيمة المرجعة، وأصبح هو المسؤول عن تحريرها في الـdestructor الخاص به.   لكن يجب الانتباه أن عملية نقل الملكية لا تقوم بعمل Deep Copy، لأن المؤشر الذكي المنسوخ منه يفقد ملكيته تماماً لموقع الذاكرة.. وبالتالي، فإن هناك أماكن يجب ألا يستخدم فيها المؤشر التلقائي، سنتحدث عنها لاحقاً. لكن أولاً، كيف نقوم بعملية نقل الملكية؟ قبل أن نكتب كود النسخ، سنكتب أولاً دالة release، ما تقوم به هذه الدالة هو إسناد قيمة NULL إلى المؤشر الخام الموجود داخل المؤشر التلقائي، ثم تقوم بإعادة موقع الذاكرة الذي كان يشار إليه في هذا المؤشر من قبل، إذاً فهذه الدالة تقوم بـ"التخلي" عن موقع الذاكرة الخاص بها لتعطيه لمن يقوم بالتقاط القيمة المرجعة من الدالة، كالتالي:           T* release()       {              T* temp= raw_ptr;              raw_ptr= 0;              return temp;       }  الآن يمكنني أن أستعمل هذه الدالة لأقوم بعملية نقل الملكية عند استدعاء copy constructor أو معامل النسخ العادي، فيصبح الكود:   template <class T>class AT_auto_ptr{private:       T* raw_ptr;public:       AT_auto_ptr(): raw_ptr(0) {}       AT_auto_ptr(T* ptr): raw_ptr(ptr) {}       AT_auto_ptr(AT_auto_ptr<T>& other): raw_ptr(other.release()) {}       ~AT_auto_ptr()       {              delete raw_ptr;       }       T& operator * () const       {              return *raw_ptr;       }       T* operator -> () const       {              return raw_ptr;       }             AT_auto_ptr& operator = (AT_auto_ptr<T>& other)       {              if (this != &other)              {                     delete raw_ptr;                     raw_ptr= other.release();              }              return (*this);       }       T* release()       {              T* temp= raw_ptr;              raw_ptr= 0;              return temp;       }};  لاحظ أننا في المعامل = قمنا أولاً بتحرير الذاكرة التي يقوم المؤشر بحجزها قبل إسناد القيمة الجديدة إليه، وذلك لتجنب حدوث تسرب في الذاكرة.   دالة أخرى مفيدة، هي دالة reset، والتي تعطي للمؤشر مكاناً جديداً في الذاكرة، بعد أن تقوم بتحرير المكان القديم، فهي تستخدم كالتالي:           auto_ptr<int> p(new int);             //Some code       p.reset(new int);  ما تقوم به هذه الدالة، هو تحرير المكان القديم المحجوز في الذاكرة وإسناد المكان الجديد للمؤشر الداخلي، إذاً يمكن أن تكون كالتالي:     void reset (T* ptr)       {              if (ptr != raw_ptr)              {                     delete raw_ptr;              }                           raw_ptr= ptr;       }  بالطبع قمنا بالتأكد من ألا يكون المكان الجديد الذي نريد أن نسنده في الذاكرة هو ذاته المكان القديم، لأنه إن كان كذلك وقمنا بتحريره، فقد خسرنا المكان الجديد والقديم في آن معاً ووقعنا في أخطاء محاولة الوصول إلى موقع من الذاكرة قد تم تحريره.... من الجيد أيضاً أن يكون لدى مستخدم المؤشر التلقائي قدرة على الوصول المباشر إلى المؤشر الخام الموجود داخله، من أجل عمليات المقارنة وغيرها، لذلك نوفر دالة get التي ببساطة تعيد العنوان الذي يشير إليه المؤشر الداخلي:     T* get()       {              return raw_ptr;       }  بالطبع إذا استخدمت هذه الدالة لأغراض شريرة، كأن تقوم بعمل:     delete p.get();  فـ"ذنبك على جنبك"  :P    يبدو درع المؤشر التلقائي درعاً ممتازاً، لكن كما قلنا من قبل، يجب أن يعرف المرء المهمة التي يريد القيام بها قبل ارتداء الدرع، لكي لا يصبح درعه سلاحاً ضده.... قد ترغب في استعمال المؤشر التلقائي كـmember داخل Class، وهذا أمر جميل حيث أن الذاكرة التي يقوم بحجزها المؤشر ستحرر عند انتهاء حياة الـobject، لكن يجب الانتباه من عمليات النسخ، لأن عملية نقل الملكية "ستقتل" المؤشر الذكي المنسوخ منه، لذلك، يجب أن نقوم بعمل نوع آخر من الـdeep copy...   class SomeClass{public:       AT_auto_ptr<int> a;       SomeClass(): a(new int) {}       SomeClass& operator = (const SomeClass& other)       {              a.reset(new int);              *a= *(other.a);              return (*this);       }};int main(){       SomeClass first;       *(first.a)= 5;       SomeClass second;       second= first;       cout<< first.a.get()<< endl;       cout<< second.a.get()<< endl;       cout<< *(first.a)<< endl;       cout<< *(second.a)<< endl;       return 0;}  هذه المشكلة قد حلت إذاً باستخدام أسلوب مشابه للـDeep Copy، لكن مشكلة أساسية تحد من قدرات المؤشر التلقائي، ألا وهي أنه من غير الممكن استعماله داخل STL Containers، حيث أن هذه الحاويات تقوم بعمليات نسخ متعددة، دون الاهتمام بكون العناصر داخلها من نوع المؤشر التلقائي، وبالتالي فإن عملية نقل الملكية ستودي إلى جعل عدد كبير من المؤشرات فارغة تشير إلى NULL، ويمكن مشاهدة ذلك بوضوح في دالة sort الموجودة في STL والتي تعتمد على خوارزمية Quick Sort، هذه الخوارزمية تقوم بنسخ أحد العناصر ووضعه في محور في كل مرة وترتيب العناصر من حوله، وفي النهاية يتم حذف هذا المحور، مما سيؤدي إلى أن تصبح كل المؤشرات في الـContainer تشير إلى NULL.... بالمختصر المفيد، لا تستخدم المؤشر التلقائي في STL Containers... بعد التفكير... جرب أن تستخدمه، لن تخسر شيئاً، لكنك لن تستطيع أصلاً أن تستخدمه لأنه تمت برمجته بطريقة تؤدي إلى صدور Compile Error عند استعماله مع دوال STL كـinsert وغيرها.... فلا مشكلة  :D      كتلخيص.... المؤشر التلقائي هو مؤشر ذكي من المفيد جداً استخدامه عندما تريد التأكد من تحرير الذاكرة. يتميز المؤشر التلقائي بخاصية نقل الملكية عند النسخ، والتي تحافظ على بقاء مؤشر واحد يشير إلى الموقع من الذاكرة، لهذه الصفة إيجابياتها وسلبياتها، ويجب الانتباه عند التعامل معها لكي لا ينتهي الأمر بفقدان ما نشير إليه بسبب عمليات النسخ غير المحسوبة....   في المرفقات كود المؤشر التلقائي الذي صنعناه. لكن يجب الملاحظة أن الهدف من هذا المؤشر هو التعليم وليس الاستخدام، لذلك استخدم auto_ptr العادي الموجود في مكتبة memory لأن المؤشر التلقائي الذي قمنا بصنعه لا يحتوي إلا على الوظائف البدائية...   سنتابع في الردود القادمة إن شاء الله مع أنواع أخرى من المؤشرات الذكية atautoptr.h
  5. أبسط الأنواع في Visual هو أن تختار New Project ثم Win32 Console Application، وتعطيه اسماً، ثم بعد ذلك تضغط Next وتختار Empty Project. بعد ذلك، يمكنك إضافة ملفات C++ عن طريق الضغط بالزر اليميني على Source Files واختيار Add ثم New Item. تختار بعدها C++ File.   ملاحظة، البرنامج الذي كتبته يطبع hello user عدداً لا نهائياً من المرات... ما الفكرة؟ :)   بالتوفيق
  6. حاويات من جوجل تحفظ الوقت والذاكرة

    http://stackoverflow.com/questions/6438086/iterator-invalidation-rules   يبدو أنني كنت مخطئاً، الـinvalidation يحصل في حاويات أخرى كـvector. أما الـmap والـset فلا يحدث فيها.
  7. حاويات من جوجل تحفظ الوقت والذاكرة

    جزاك الله خيراً، لدي سؤال:   Unlike the standard container types, insertions and deletions invalidate outstanding iterators   ألا يحدث هذا في الـSTL Containers أيضاً؟
  8. قبل أن تقرأ:يعد بحث المؤشرات الذكية من البحوث المتقدمة في لغة سي بلس بلس، لذلك يفضل قبل أن تقرأ هذا الموضوع أن تكون على مستوى فوق المتوسط في هذه اللغة، وأن تكون مرتاحاً في التعامل مع جوانبها المختلفة.سأحاول في هذا البحث أن أشرح المؤشرات الذكية، فوائدها، أنواعها من حيث التصميم والاستعمال، وما يتوفر منها في مكتبات STL وBOOST إن تيسرهذا البحث مجهود شخصي، قمت فيه بمراجعة بعض المراجع التي سأعددها بعد انتهائه، وبالتالي أرجو أن تصلّحوا لي إن أخطأت في أي أمر (لغوي أو معنويأو شرحي) ليصل الموضوع إلى المستوى الأفضل.سأقسم الموضوع إلى مراحل لسهولة القراءة، وأيضاً لكي لا أصاب بالملل فأتوقف عن تتمته.إن أفدت في هذا فأرجو أن تدعوا لي أن يهديني الله ويقومني لأن هذا أكثر ما أحتاجه.. مقدمة:المؤشرات الذكية؟ هل يعني هذا أن هناك مؤشرات ذكية وأخرى وغبية؟ليس تماماً، لكن لنقل إن المؤشرات الذكية كما يقال باللهجة السورية "بتعرف تدبر راسها"، فهي تتميز بقدرتها على إدارة أمور الذاكرة بنفسها كما سنرى، أما المؤشرات العادية، فهي "بتغرق بشبر مَي" تحتاج إلى أن يقوم المبرمج بنفسه بإدارة أمورها من حذف ونسخ وغير ذلك.لا أقصد هنا بالطبع الهجوم على المؤشرات العادية، فهي كما سنرى تشكل البنية التحتية للمؤشرات الذكية، لكن ما أقصده أن المؤشرات الذكية هي أدوات تقوم بأتمتة بعض العمليات الخاصة بالمؤشرات، وتريح المبرمج بالتالي من القيام بهذه العمليات بشكل يدوي. المؤشرات الذكية؟ لماذا؟ببساطة... لأن الأطباء العصبيين والنفسيين مكلفون جداً....ومن المكلف على الشركة أن ترسل لهم كل حين مبرمج سي بلس بلس مسكيناً قد تلفت أعصابه بعد ساعات وربما أيام من البحث والتنقيب عن خطأ سببه أحد المؤشرات التي يستعملها....إن السبب الذي ينفر الكثيرين من سي بلس بلس، هو مشاكل المؤشرات فيها. فعلى الرغم من المرونة الهائلة التي توفرها المؤشرات، إلا أن قلة الخبرة والانتباه في استخدامها قد تؤدي إلى مشاكل عديدة، تحتاج إلى ساعات وساعات من البحث والـDebugging لحلها. من مشاكل المؤشرات في سي بلس بلس: يجب أن يقابل كل كلمة new، كلمة delete. وإلا فإن البرنامج سيستهلك مساحات من الذاكرة أكبر بكثير مما يحتاجه، فيما يعرف بـMemory Leakage، أو تسرب الذاكرة. مشكلة Shallow Copying، أو النسخ السطحي، والتي تحدث بكثرة في الكلاسات التي تحوي في داخلها مؤشرات. أحياناً تكون هذه المشكلة واضحة، وأحياناً أخرى تكون أقل وضوحاً، كالمثال التالي:  #include <vector>using namespace std;class Example{public: int* p; Example(): p(new int) {} ~Example() { delete p; }};int main(){ vector<Example> a; a.push_back(Example()); return 0;}    عندما تشغل هذا الكود على Microsoft Visual Studio، سيرمي لك استثناء، وإذا تتبعت المشكلة بالـDebugger، ستجد أنها تحدث عندما نقوم بعمل delete للمؤشر الموجود في Example، لكن ما الذي حدث؟الذي حدث أننا عندما أعطينا push_back وسيطاً، هو الـDefault Constructor الخاص بـExample، تم إنشاء كائن مؤقت من Example وتهيئته، ثم تم نسخه إلى العنصر الأول في الـvector واستدعي الـDestructor الخاص به عندما انتهت push_back، وبالتالي فقد تم تحرير الذاكرة التي حجزها المؤشر، وحدثت مشكلة النسخ السطحي، دون أن ننتبه لها، مما سبب حدوث الخطأ. فعند انتهاء main، سيتم تدمير عناصر الـvector، وسيستدعى الـDestructor مرة أخرى، ليقوم بدوره باستدعاء delete على المؤشر نفسه مرة أخرى... بالطبع لحل الخطأ نقوم بعمل نسخ عميق Deep Copy، يجنبنا هذه المشكلة:#include <vector>using namespace std;class Example{public: int* p; Example(): p(new int) {} Example(const Example& other) { p= new int; *p= *(other.p); } ~Example() { delete p; }};int main(){ vector<Example> a; a.push_back(Example()); return 0;}     مشكلة المؤشرات الجامحة Stray Pointers، التي تم تحرير الذاكرة التي حجزتها (بواسطة delete)، لكن لم يتم تصفيرها (إسناد القيمة NULL أو 0 إليها)، والتي تحدث غالباً عند حدوث الـShallow Copy، الكود السابق هو مثال عليها، حيث تم حذف المؤشر، ومن ثم تمت محاولة إعادة حذفه مرة أخرى، مما سبب الخطأ. مثال آخر على الـMemory Leak، كما هو من مقالة: Smart Pointers - What, Why, Which? void foo(){ MyClass* p(new MyClass); p->DoSomething(); delete p;}     لنفترض أن استدعاء DoSomthing سبب رمي استثناء ما. فإن السطر delete p;    لن ينفذ، وبالتالي لن يستدعى الـDestructor الخاص بـMyClass، وبناء على ما يفعل هذا الـDestructor، ستكون النتائج....حيث أن هذا الـDestructor قد يحرر موارد عديدة في الذاكرة ويسند قيماً، ويعلم برامج أخرى ووو، كل هذا لن يحدث لأن التنفيذ لم يصل إلى جملة delete... هناك مشاكل أخرى كثيرة تظهر عند التعامل مع المؤشرات. ولا ندّعي، أن أياً من هذه المشاكل لا يمكن حلها، ولكنها قد تكلف الشركة أطناناً من القهوة وفواتيراً من الأطباء العصبيين! إذاً... ما الحل؟الحل المباشر.... الحذر في التعامل ومعرفة ما تقوم به في كل لحظة. لكن هذا غير كافٍ، فمن طبيعة الإنسان الخطأ. أيضاً... لماذا لا يكون لديك أداة تريحك من عناء المتابعة والتدقيق؟؟هنا تأتي المؤشرات الذكية فما هي المؤشرات الذكية؟؟؟؟تخيل أنك تلعب لعبة كمبيوتر، أنت فيها قائد مجموعة سرية، تقوم بإجراء المهمات الصعبة في الكواكب الأخرى بتكليف من حكومة الأرض.لكل مهمة، ترسل واحداً من عملائك السريين، بعد أن تعطيه درعاً يساعده على القيام بالمهمة... هناك دروع مختلفة، فهناك درع الإخفاء، ودرع تسريع الحركة، ودرع الحماية من الحرارات المرتفعة.. إلخبالطبع كلاعب محترف، لن تقوم بإرسال العميل إلى كوكب قريب من الشمس إلا بالدرع الذي يقي من الحرارة المرتفعة، ولن تعطيه درع الإخفاء إذا كان لدى الكوكب الآخر حساسات حرارية تلتقط أجسام البشر. وبالتأكيد، فإن درع السرعة هو الأنسب عندما يكون الوقت ضيقاً. ما المقصود من هذا كله؟ إن العميل هو المؤشر العادي الذي نعرفه، والمهمة السرية هي ما سيقوم به هذا المؤشر من حجز وتحرير للذاكرة وغير ذلك.أما الدرع، فهو المؤشر الذكي، فالمؤشر الذكي لا يعدو عن كونه "غلافاً" يحيط بالمؤشر ليساعده على القيام بمهامه، وكما رأينا، فإن للمؤشر الذكي أنواعاً، نختار المناسب منها حسب المهام التي نريد من المؤشر القيام بها. المؤشر الذكي هو Class يحوي بداخله مؤشراً عادياً، ومتغيرات أخرى ربما، كما يحوي بداخله العديد من الـFunctions التي تدير التعامل مع المؤشر الداخلي. ما فوائد هذه المؤشرات الذكية؟فوائدها كثيرة، نحصي بعضاً منها:إدارة الذاكرة... فبعض أنواع المؤشرات الذكية تحرص على أن لا يشير إلى المنطقة الواحدة من الذاكرة أكثر من مؤشر واحد، وعندما ينتهي عمر هذه المؤشرات فإنها تقوم تلقائياً بتحرير الذاكرة. نوع آخر من المؤشرات يسمح لأكثر من مؤشر أن يشيروا إلى المكان ذاته في الذاكرة، ولا يحرره إلا عندما ينتهي عمر آخر مؤشر كان يشير إليه. إذاً، فإن هذه المؤشرات تقوم بتقليل احتمالية حدوث الـBugs الخاصة بالذاكرة، كما تقوم بالـGarbage Collection لتجنب الـMemory Leakage.التوفير في استهلاك الذاكرة... فلنفترض أننا قمنا بالتأشير بأحد المؤشرات إلى كائن كبير جداً، ثم أردنا نسخه، فإن هذا يعني أنه سيصبح لدينا نسختان من هذا الكائن في الذاكرة، وعندما ننسخه عشر مرات فسيصبح لدينا عشر نسخ... أحد أنواع المؤشرات الذكية، يقوم بحل مشكلة كهذه بطريقة "ذكية"، فهو كما سنرى يقوم عند النسخ بجعل كل المؤشرات تشير إلى الكائن نفسه في الذاكرة، لكن عندما يحاول أحد هذه المؤشرات إجراء أي تعديل على الكائن، يقوم بإنشاء نسخة جديدة لهذا المؤشر ثم يجري التعديلات على النسخة، بينما تبقى المؤشرات الأخرى كلها تشير إلى النسخة الأصلية، مما يوفر الكثير من الذاكرة.ويمكننا القول إن فوائد المؤشرات الذكية غير محدودة، فأي مشكلة يواجهها المرء مع المؤشرات، يمكن أن يصمم لها مؤشراً ذكياً جديداً يقوم بحلها، ومن يدري... ربما يقوم أحد قارئي هذا المقال بتصميم مؤشر جديد يحل مشكلة أدت في يوم من الأيام إلى ارتفاع كبير في نسبة الصلع في العالم!! في الردود القادمة، سأقوم إن شاء الله بشرح الأنواع المشهورة من المؤشرات الذكية، وكيفية تصميمها واستعمال الجاهز منها، أرجو أن يكون في ذلك الفائدة.... لكن أمهلوني بعض الوقت :) والسلام عليكم ورحمة الله....
  9. بالنسبة للمعامل الثلاثي فهذا مثال على استخدامه:    int x;cin>> x; int Abs; Abs= x >= 0? x : -x; cout<< Abs;   في هذا الكود نطبع القيمة المطلقة للعدد الذي يتم إدخاله.   هذا الكود يتحقق إذا كان x أكبر أو يساوي الصفر، فعندها يضع القيمة x في Abs، وإلا فإنه يضع فيها القيمة -x يمكن تطبيقه كما هو في جملة if، بشكل عادي.   الـSyntax الخاص به هو كالتالي:   The condition to be tested? The value to be returned if the condition evaluates to true : The value to be returned if the condition evaluates to false;  تمام؟ :)
  10. أحسنت بالتوفيق إن شاء الله ولا تخجل من وضع الأسئلة على المنتدى عندما تحتاج، طبعاً بعد الكثير من المحاولة ;)
  11. أولاً أخي، مبارك عليك هذه الهمة والأهداف العالية، لكن الأفضل أن تبقي برمجة نظم التشغيل وهذه الأمور في الأفق، بينما تضع أهدافاً مرحلية أصغر، لكي لا تحبط وأنت تحاول الوصول إلى هدفك البعيد. يعني ضع هدفاً صغيراً لبعد شهر، ثم هدفاً أكبر قليلاً لشهرين، وهكذا، أما الوصول إلى برمجة نظم التشغيل، فضعه بعيداً، لا أريد أن أحبطك، لكن لأضعك في الأمر الواقع، ضعه لبعد عشر سنوات تقريباً....   بالنسبة للبدء بتعلم البرمجة، أولاً اختر لغة، لنقل C++، ثم ركز على تعلم هذه اللغة، وعلى تعلم كيفية البرمجة، ولاحظ أن الأمرين منفصلان، فهناك من يعرف الكثير من البرمجة، دون أن يعرف أي لغة برمجة، فالبرمجة طريقة تفكير، أما اللغة فهي أداة. لبدء البرمجة بـC++ هناك كتب كثيرة، شخصياً أنصح بـSAMS Teach Yourself C++ in One Hour A Day والكتاب عن تجربة شخصية، أكثر من رائع. ركز أثناء تعلمك، على تكوين أكبر قدر ممكن من الخبرة، حل أكبر عدد من الأسئلة النظرية والتمارين العملية والمسائل، وحاول أن تشارك غيرك في المشاريع الصغيرة، لتبني خبرتك وتراكمها، وحاول أيضاً أن تجيب على أسئلة الآخرين في المنتدى، فهذا يمنحك خبرة لا بأس بها.   أخيراً، عليك بإتقان اللغة الإنكليزية قدر المستطاع، فمن دون اللغة الإنكليزية ستستطيع تعلم البرمجة، لكنك ستصل إلى حد تقف عنده.   مبدئياً، امض بتعلم لغة C++ حتى تشعر أنك أصبحت مرتاحاً في استعمالها، ثم فكر كيف تكمل.....   نصيحة جانبية ليس لها علاقة بالبرمجة، ضع خطة عمل لنفسك، ونظام مكافئات وعقوبات، وجدولاً زمنياً، لا تترك نفسك للعشوائية في العمل أو للحماس لأن الحماس يفتر بعد حين... بالتوفيق
  12. شكراً لك أخي الكريم، اسمحلي أن أضيف هنا بعض فوائد الـStack واستخداماته:   لنفترض أنك تريد أن تحل متاهة، فإنك تدخل كل خطوة في المتاهة في الـStack، أي تقوم بعمل push، وعندما تصل إلى نهاية مسدودة، فإنك تقوم بعمل pop لآخر خطوة قمت بها وتختار خطوة أخرى بدلاً منها، إذاً فحل المتاهة يعتمد على أنك ستتخذ سلسلة من القرارات، وعندما تكتشف أنك وصلت إلى نتيجة خاطئة، فإنك تعمل pop لآخر قرار وتتخذ قراراً آخر وتعيد التجربة، إلى أن تصل إلى النهاية المرادة للمتاهة. يمكنك تطبيق الأمر ذاته على حل لعبة الـSudoko، حيث يمكنك أن تجعل الحاسوب يتخذ سلسلة من القرارات، وعندما يجد أنه وصل إلى نتيجة خاطئة، يتراجع عن آخر قرار ويغير مساره، إلى أن يصل إلى النتيجة الصحيحة، يدعى هذا الأسلوب بالـBackTracking.   استخدام آخر للـStack هو في تحليل الأقواس في العمليات الحسابية، فعندما ترى:  (3 + 5(8 + 4))فإن الـstack سيساعد البرنامج على تحديد أن أول قوس إغلاق هو لإغلاق آخر قوس فتح تم إدخاله في الـstack. أي أن أول قوس ) سيراه، هو لإغلاق العملية (8 + 4) وليس لإغلاق العملية الكاملة.   أما أهم استخدامات الـstack فهي الخوارزميات التي تعتمد على الـrecursion، ويمكنك النظر إلى أي كود يحتوي recursion لتجد أن هناك stack لا تراه يقوم بإدارة العملية، ويرتب الأمور بحيث أن آخر استدعاء للـfunction هو أول استدعاء سيعيد نتيجة، حلل هذا الكود لترى كيف يعمل بأسلوب الـstack، وإن كنت لا ترى الـstack أمامك، فإنه يستعمل ما يدعى بـfunction stack: int pow(int x, int y){if (y == 0)return 1;return x * pow(x, y - 1);}if (y == 0)   بشيء من التحليل لهذا الكود، سترى أن هناك stack يقوم بعمل معين وراء الكواليس، يمكنك حقيقة الاستفادة من هذا الـstack بشكل كبير. على سبيل المثال، إذا أردت برنامجاً تدخل إليه الرقم 4 مثلاً، فيطبع: **** *** ** * * ** *** **** بعد قليل من النظر، ستلاحظ أنك لو أدخلت في stack السطور الأربعة الأولى ثم أخرجتها من الآخر إلى الأول، فستحصل على ما تريده تماماً، ويمكننا استعمال الـFunction stack كالتالي:  void StackExample(int n){if (n == 0)return; for (int i= 0; i < n; i++)cout<< "*";cout<< endl; StackExample(n - 1); for (int i= 0; i < n; i++)cout<< "*";cout<< endl; }يمكنك أن تنظر للاستدعاء العودي للدالة على أنه عمل push في الـfunction stack، بينما انتهاء الدالة هو عمل pop.   أرجو أن تكون الأمثلة مفيدة ووضحت شيئاً من قيمة الـstack في البرمجة   وشكراً لك أستاذ على هذه الدروس :)
  13. جزاك الله خيراً على هذه المعلومات المفيدة،   ذكرتني بسؤال الامتحان النهائي في مادة الـData Structures، وهو عن كيفية محاكاة Queue باستخدام زوج من الـ stacks. حدا عندو فكرة؟ :)   اسمح لي بأن أضيف على موضوعك بعض فوائد الـQueue ولماذا نستخدمه: نستخدم الـQueue عندما يكون عندنا مجموعة من التعليمات أو الأمور التي نريد تنفيذها حسب ترتيب وصولها إلينا، فمثلاً لو كنت تبرمج برنامجاً يقوم بتحويل المتصلين إلى عاملة الهاتف لترد عليهم، فيمكنك أن تضع المتصلين في queue حسب أولوية اتصالهم، حيث يكون اتصال شخص جديد هو enqueue، بينما قيام العاملة بالرد على الشخص التالي فهو الـdequeue.   أما المثال الأروع على استخدام الـQueue فيصعب شرحه هنا، لكنه يفيد في موضوع الـGraphs فيما يعرف بـBreadth First Traversal أو لندعه المرور على الأقرب فالأبعد. مثال من الحياة الواقعية على هذه العملية، هو إذا كنت تريد أن تعرف مدى بعدك، او كم عدد الأصدقاء بينك وبين شخص مشهور س مثلاً. فإذا كان س هو صديق صديق صديقك، المسافة بينكما هي 3. تقوم هذه العملية بالنظر إلى كل أصدقائك، فإذا كان أحدهم فالمسافة بينكما 1، وإلا فإن العملية تنظر إلى كل أصدقائهم، فإذا كان أحدهم فإن المسافة بينكما 2، وإلا..... وهكذا حتى تجده، وبالتالي فنحن نمر من الأصدقاء الأقرب إلى الأبعد. طبعاً كيف تستخدم الـQueue في هذا؟ الجواب يحتاج إلى معرفة بالـGraphs لذلك ليس من السهل شرحه هنا، ولكن أبق في بالك أن الـQueues أمر رائع ويجب أن تتعلمه، وسوف ترى كيفية استخدامه مع الـGraphs في المستقبل إن شاء الله :P   شكراً لك مرة أخرى أستاذ على هذه السلسلة :) 
  14. السلام عليكم، أخي المراد من برنامجك غير واضح تماماً، أرجو أن توضحه أكثر وبالتفصيل الممل.   وشكراً لك