سؤال

لقد تعلمت في الكلية أنه يتعين عليك دائمًا تحرير العناصر غير المستخدمة، ولكن ليس كيفية القيام بذلك بالفعل.على سبيل المثال، تنظيم التعليمات البرمجية الخاصة بك بشكل صحيح وما إلى ذلك.هل هناك أي قواعد عامة حول كيفية التعامل مع المؤشرات في C++؟

لا يُسمح لي حاليًا باستخدام التعزيز.يجب أن ألتزم باستخدام لغة c++ النقية لأن إطار العمل الذي أستخدمه يمنع أي استخدام للأدوية العامة.

هل كانت مفيدة؟

المحلول

لقد عملت مع نظام التشغيل Symbian OS المضمن، والذي كان لديه نظام ممتاز لهذا الغرض، يعتمد بالكامل على اتفاقيات المطورين.

  1. كائن واحد فقط سوف يمتلك المؤشر.افتراضيا هذا هو الخالق.
  2. يمكن نقل الملكية.للإشارة إلى تمرير الملكية، يتم تمرير الكائن كمؤشر في توقيع الطريقة (على سبيل المثال.باطلة فو (بار * زونك)؛).
  3. سيقرر المالك متى سيتم حذف الكائن.
  4. لتمرير كائن إلى طريقة للاستخدام فقط، يتم تمرير الكائن كمرجع في توقيع الطريقة (على سبيل المثال:باطلة فو (بات &زونك)؛).
  5. قد تقوم الفئات غير المالكة بتخزين مراجع (ليست مؤشرات أبدًا) للكائنات التي يتم تقديمها لها فقط عندما تكون متأكدة من أن المالك لن يدمرها أثناء الاستخدام.

في الأساس، إذا كان الفصل يستخدم شيئًا ما، فإنه يستخدم مرجعًا.إذا كان الفصل يمتلك شيئًا ما، فإنه يستخدم المؤشر.

لقد عمل هذا بشكل جميل وكان من دواعي سروري استخدامه.كانت مشاكل الذاكرة نادرة جدًا.

نصائح أخرى

قواعد:

  1. حيثما أمكن، استخدم أمؤشر ذكي.دفعة لديه بعضجيدة.
  2. إذا لم تتمكن من استخدام مؤشر ذكي ، إلغاء مؤشرك بعد حذفه.
  3. لا تعمل أبدًا في أي مكان لا يسمح لك باستخدام القاعدة 1.

إذا لم يسمح شخص ما بالقاعدة 1، فتذكر أنه إذا حصلت على كود شخص آخر، وقمت بتغيير أسماء المتغيرات وحذف إشعارات حقوق الطبع والنشر، فلن يلاحظ أحد ذلك على الإطلاق.إلا إذا كان مشروعًا مدرسيًا، حيث يتحققون بالفعل من هذا النوع من الخدع باستخدام أدوات متطورة جدًا.أنظر أيضا، هذا السؤال.

وأود أن أضيف قاعدة أخرى هنا:

  • لا تقم بجديد/حذف كائن عندما يكون الكائن التلقائي يعمل بشكل جيد.

لقد وجدنا أن المبرمجين الجدد في لغة C++، أو المبرمجين القادمين من لغات مثل Java، يبدو أنهم يتعلمون أشياء جديدة ثم يستخدمونها بقلق شديد عندما يريدون إنشاء أي كائن، بغض النظر عن السياق.يعد هذا أمرًا ضارًا بشكل خاص عندما يتم إنشاء كائن محليًا داخل وظيفة فقط للقيام بشيء مفيد.قد يكون استخدام الجديد بهذه الطريقة ضارًا بالأداء ويمكن أن يجعل من السهل جدًا حدوث تسرب سخيف للذاكرة عند نسيان الحذف المقابل.نعم، يمكن للمؤشرات الذكية أن تساعد في الحل الأخير ولكنها لن تحل مشكلات الأداء (بافتراض استخدام جديد/حذف أو ما يعادله خلف الكواليس).ومن المثير للاهتمام (ربما)، أننا وجدنا أن الحذف غالبًا ما يكون أكثر تكلفة من الجديد عند استخدام Visual C++.

بعض هذا الالتباس يأتي أيضًا من حقيقة أن الوظائف التي يستدعونها قد تأخذ مؤشرات، أو حتى مؤشرات ذكية، كوسائط (في حين أن المراجع ربما تكون أفضل/أكثر وضوحًا).وهذا يجعلهم يعتقدون أنهم بحاجة إلى "إنشاء" مؤشر (يبدو أن الكثير من الناس يعتقدون أن هذا هو ما يفعله الجديد) حتى يتمكنوا من تمرير المؤشر إلى دالة.من الواضح أن هذا يتطلب بعض القواعد حول كيفية كتابة واجهات برمجة التطبيقات لجعل اصطلاحات الاتصال غير غامضة قدر الإمكان، والتي يتم تعزيزها بتعليقات واضحة مقدمة مع النموذج الأولي للوظيفة.

في الحالة العامة (إدارة الموارد، حيث لا يكون المورد بالضرورة ذاكرة)، يجب أن تكون على دراية بـ نمط راي.هذه واحدة من أهم المعلومات لمطوري C++.

بشكل عام، تجنب التخصيص من الكومة إلا إذا لزم الأمر.إذا كان عليك ذلك، فاستخدم العد المرجعي للكائنات طويلة العمر والتي تحتاج إلى المشاركة بين أجزاء متنوعة من التعليمات البرمجية الخاصة بك.

في بعض الأحيان تحتاج إلى تخصيص الكائنات ديناميكيًا، ولكن لن يتم استخدامها إلا خلال فترة زمنية معينة.على سبيل المثال، في مشروع سابق كنت بحاجة إلى إنشاء تمثيل معقد لمخطط قاعدة بيانات في الذاكرة - وهو في الأساس رسم بياني دوري معقد للكائنات.ومع ذلك، كان الرسم البياني مطلوبًا فقط طوال مدة الاتصال بقاعدة البيانات، وبعد ذلك يمكن تحرير جميع العقد في طلقة واحدة.في هذا النوع من السيناريو ، يكون النمط الجيد لاستخدامه هو شيء أسميه "تعبير GC المحلي". لست متأكدًا مما إذا كان له اسم "رسمي" ، لأنه شيء رأيته فقط في الكود الخاص بي ، وفي الكاكاو (انظر NSAutoreleasePool في مرجع الكاكاو الخاص بشركة Apple).

باختصار، يمكنك إنشاء كائن "مجمع" يحتفظ بمؤشرات للكائنات المؤقتة التي تقوم بتخصيصها باستخدام كائنات جديدة.عادةً ما يكون مرتبطًا ببعض النطاقات في برنامجك، إما نطاقًا ثابتًا (على سبيل المثال.- ككائن مخصص للمكدس يطبق مصطلح RAII) أو كائن ديناميكي (على سبيل المثال.-- مرتبط بعمر اتصال قاعدة البيانات، كما في مشروعي السابق).عندما يتم تحرير الكائن "المجمع"، فإن أداة التدمير الخاصة به تحرر كافة الكائنات التي يشير إليها.

أيضًا، مثل DrPizza، أعتقد أن القيود المفروضة على عدم استخدام القوالب قاسية جدًا.ومع ذلك، بعد إجراء الكثير من التطوير على الإصدارات القديمة من Solaris وAIX وHP-UX (مؤخرًا - نعم، لا تزال هذه الأنظمة الأساسية موجودة في قائمة Fortune 50)، يمكنني أن أخبرك أنه إذا كنت مهتمًا حقًا بإمكانية النقل، فعليك يجب استخدام القوالب بأقل قدر ممكن.يجب أن يكون استخدامها للحاويات والمؤشرات الذكية أمرًا جيدًا (لقد نجح الأمر بالنسبة لي).بدون القوالب، يكون تنفيذ التقنية التي وصفتها أكثر إيلامًا.قد يتطلب الأمر أن تكون جميع الكائنات التي يديرها "المجمع" مستمدة من فئة أساسية مشتركة.

يوم سعيد،

أقترح قراءة الأقسام ذات الصلة من كتاب "Effective C++" بقلم سكوت مايرز.سهل القراءة وهو يغطي بعض الأخطاء المثيرة للاهتمام لاحتجاز الغافلين.

أنا مفتون أيضًا بنقص القوالب.لذلك لا يوجد STL أو Boost.رائع.

راجع للشغل جعل الناس يتفقون على الاتفاقيات هي فكرة ممتازة.كما هو الحال مع جعل الجميع يتفقون على اتفاقيات OOD.راجع للشغل، الإصدار الأخير من C++ الفعال لا يحتوي على الفصل الممتاز حول اتفاقيات OOD التي كانت موجودة في الإصدار الأول وهو أمر مؤسف، على سبيل المثال.الاتفاقيات مثل الميراث الظاهري العام دائماً نماذج لعلاقة "ISA".

روب

  • عندما يتعين عليك استخدام إدارة الذاكرة يدويا ، تأكد من استدعاء حذف في نفس الوقت النطاق / الوظيفة / الفئة / الوحدة النمطية ، والتي ينطبق أولا ، على سبيل المثال:
  • دع المتصل في وظيفة تخصيص الذاكرة المملوءة بها ، لا تُرجع مؤشرات جديدة.
  • قم دائمًا باستدعاء الحذف في نفس ملف exe/dll الذي قمت باستدعاء الجديد فيه، وإلا فقد تواجه مشاكل مع تلف الكومة (مكتبات وقت التشغيل المختلفة غير المتوافقة).

يمكنك استخلاص كل شيء من بعض الفئات الأساسية التي تنفذ وظيفة مثل المؤشر الذكي (باستخدام أساليب ref ()/unref () والعداد.

جميع النقاط التي أبرزها @Timbo مهمة عند تصميم تلك الفئة الأساسية.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top