سؤال

تدور لغة C++ حول ملكية الذاكرة
الملقب ب "دلالات الملكية"

وتقع على عاتق مالك جزء من الذاكرة المخصصة ديناميكيًا تحرير تلك الذاكرة.لذا فإن السؤال يصبح حقًا من يملك الذاكرة.

في لغة C++، يتم توثيق الملكية حسب النوع الذي يتم تغليف مؤشر RAW بالداخل وبالتالي في برنامج C++ جيد (IMO) فمن النادر جدًا [نادر وليس أبدًا] رؤية مؤشرات RAW يتم تمريرها (نظرًا لأن مؤشرات RAW ليس لها ملكية مستنتجة وبالتالي لا يمكننا ذلك) أخبر من يملك الذاكرة، وبالتالي بدون قراءة متأنية للوثائق، لا يمكنك معرفة من المسؤول عن الملكية).

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

إذن السؤال:

  • ما هو نوع الملكية الدلالية التي صادفها الناس؟
  • ما هي الفئات القياسية المستخدمة لتنفيذ تلك الدلالات؟
  • ما هي المواقف التي تجدها مفيدة؟

دعونا نحتفظ بنوع واحد من الملكية الدلالية لكل إجابة حتى يمكن التصويت عليها لأعلى ولأسفل بشكل فردي

ملخص:

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

الأمراض المنقولة جنسيا::auto_ptr<T>:

شخص واحد يملك الكائن.
لكن نقل الملكية مسموح به.

الاستخدام:
======
يتيح لك ذلك تحديد الواجهات التي تعرض النقل الصريح للملكية.

دفعة::scoped_ptr<T>

شخص واحد يملك الكائن.
نقل الملكية غير مسموح به.

الاستخدام:
======
يُستخدم لإظهار الملكية الصريحة.
سيتم تدمير الكائن بواسطة المدمر أو عند إعادة تعيينه بشكل صريح.

دفعة::shared_ptr<T> (std::tr1::shared_ptr<T>)

ملكية متعددة.
هذا هو مؤشر مرجعي بسيط.عندما يصل العدد المرجعي إلى الصفر، يتم تدمير الكائن.

الاستخدام:
======
عندما يمكن أن يحتوي الكائن على عدة زهرات بعمر لا يمكن تحديده في وقت الترجمة.

دفعة::weak_ptr<T>

يستخدم مع Shared_ptr<T>.
في المواقف التي قد تحدث فيها دورة من المؤشرات.

الاستخدام:
======
يُستخدم لإيقاف الدورات من الاحتفاظ بالكائنات عندما تكون الدورة فقط هي التي تحافظ على إعادة العد المشتركة.

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

المحلول

بالنسبة لي، هذه الأنواع الثلاثة تغطي معظم احتياجاتي:

shared_ptr - عد المرجع، إلغاء التخصيص عندما يصل العداد إلى الصفر

weak_ptr - نفس ما ورد أعلاه، لكنه "عبد" ل shared_ptr, ، لا يمكن إلغاء التخصيص

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

لدي تطبيقي الخاص لهذه، ولكنها متوفرة أيضًا في Boost.

ما زلت أقوم بتمرير الكائنات حسب المرجع (const كلما أمكن ذلك)، في هذه الحالة يجب أن تفترض الطريقة المستدعى أن الكائن حي فقط أثناء وقت الاستدعاء.

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

نصائح أخرى

نموذج C++ البسيط

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

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

في هذا النموذج، يتم تداول المؤشرات الأولية بحرية وفي الغالب ليست خطيرة (ولكن إذا كان المطور ذكيًا بما فيه الكفاية، فسوف يستخدم المراجع بدلاً من ذلك كلما أمكن ذلك).

  • مؤشرات خام
  • الأمراض المنقولة جنسيا::auto_ptr
  • دفعة::scoped_ptr

نموذج C++ الذكي المدبب

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

  • دفعة::shared_ptr
  • دفعة::weak_ptr

خاتمة

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

ليس لديك ملكية مشتركة.إذا قمت بذلك، فتأكد من أن ذلك يتعلق فقط بالرمز الذي لا تتحكم فيه.

وهذا يحل المشاكل بنسبة 100%، لأنه يجبرك على فهم كيفية تفاعل كل شيء.

  • ملكية مشتركة
  • دفعة::shared_ptr

عندما تتم مشاركة المورد بين كائنات متعددة.يستخدم التعزيز Share_ptr العد المرجعي للتأكد من إلغاء تخصيص المورد عند الانتهاء من الجميع.

std::tr1::shared_ptr<Blah> غالبًا ما يكون هذا هو أفضل رهان لك.

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

في نظام التشغيل Windows، توجد مؤشرات COM (IUnknown وIDispatch والأصدقاء)، والعديد من المؤشرات الذكية للتعامل معها (على سبيل المثال.ATL CComPtr والمؤشرات الذكية التي يتم إنشاؤها تلقائيًا بواسطة عبارة "الاستيراد" في Visual Studio استنادًا إلى _com_ptr فصل).

  • مالك واحد
  • دفعة::scoped_ptr

عندما تحتاج إلى تخصيص الذاكرة ديناميكيًا ولكنك تريد التأكد من إلغاء تخصيصها في كل نقطة خروج من الكتلة.

أجد هذا مفيدًا لأنه يمكن إعادة تركيبه بسهولة وتحريره دون الحاجة إلى القلق بشأن التسرب

لا أعتقد أنني كنت في وضع يسمح لي بمشاركة الملكية في تصميمي.في الواقع، الحالة الوحيدة الصالحة التي يمكنني التفكير فيها من أعلى رأسي هي نمط وزن الذبابة.

yasper::ptr هو بديل خفيف الوزن، Boost::shared_ptr.إنه يعمل بشكل جيد في مشروعي الصغير (في الوقت الحالي).

في صفحة الويب على http://yasper.sourceforge.net/ تم وصفه على النحو التالي:

لماذا أكتب مؤشر ذكي آخر لـ C++؟يوجد بالفعل العديد من تطبيقات المؤشرات الذكية عالية الجودة لـ C ++ ، وأبرزها مؤشر Boost Pantheon و Loki's SmartPtr.لمقارنة جيدة لتطبيقات المؤشرات الذكية وعندما يكون استخدامها مناسبًا ، يرجى قراءة Herb Sutter's The New C ++:المؤشرات الذكية (إيه).على النقيض من الميزات الموسعة للمكتبات الأخرى ، فإن Yasper هو مؤشر عد مرجعي يركز بشكل ضيق.إنه يتوافق بشكل وثيق مع سياسات Boost المشتركة و Loki التي تم إعادة تشكيلها/إبداعها.يسمح Yasper لمبرمجي C ++ بنسيان إدارة الذاكرة دون تقديم تبعيات Boost الكبيرة أو الاضطرار إلى التعرف على قوالب السياسة المعقدة في Loki.فلسفة

* small (contained in single header)
* simple (nothing fancy in the code, easy to understand)
* maximum compatibility (drop in replacement for dumb pointers)

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

هناك شكل آخر شائع الاستخدام للمالك الفردي القابل للتحويل، وهو الأفضل auto_ptr لأنه يتجنب المشاكل التي يسببها auto_ptrالفساد المجنون لدلالات المهمة.

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

(إنه مرجع ذكي وليس مؤشرًا ذكيًا لأنك لا تحتاج إلى إلغاء الإشارة إليه بشكل صريح للحصول على المحتوى.)

وهذا يعني أن auto_ptr يصبح أقل أهمية - فهو مطلوب فقط لملء الفجوات حيث لا تحتوي الأنواع على قيمة swap وظيفة.لكن جميع الحاويات القياسية تفعل ذلك.

  • مالك واحد:ويعرف أيضا باسم حذف على نسخة
  • الأمراض المنقولة جنسيا::auto_ptr

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

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