استخدام Boost::shared_ptr في الواجهة العامة للمكتبة

StackOverflow https://stackoverflow.com/questions/335330

  •  22-07-2019
  •  | 
  •  

سؤال

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

يحرر:لقد قلت في الأصل نقل الملكية، ولكن كان يجب أن أحدد أن الكود الموجود على جانبي حدود واجهة برمجة التطبيقات يحتاج إلى الاحتفاظ بمؤشر للكائن.

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

المحلول

Share_ptr<> يكون جزء من اللغة، اعتبارًا من إصدار TR1.يرى: (TR1)

نصائح أخرى

أحد الحلول الممكنة هو شحن Boost::shared_ptr مع مشروعك.نظرًا لأن كل ذلك يتكون من رؤوس، فإن هذا من شأنه أن يحرر عملائك من الاضطرار إلى تثبيت مكتبات التعزيز يدويًا.يمكنك استخدام bcp للحصول على كافة الملفات التي تحتاجها مكتبة تعزيز معينة، بما في ذلك المكتبات نفسها.لقد فعلت ذلك عندما كنت أعمل في شركة في ذلك الوقت وكنت بحاجة إليها boost::shared_ptr وقد نجحت بالفعل بشكل كبير.

إذا كانت الدلالات هي حقا نقل ملكية, لماذا لا تستخدم auto_ptr لأنه معيار C++؟داخليًا، لا يزال بإمكانك إنشاء Shared_ptr الخاص بك من auto_ptr ثم الحصول على ملكية مشتركة إذا كنت في حاجة إليها.

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

أنا شخصياً أعتقد أنه يجب عليك تجنب وجود الكثير من لغة C++ غير التقليدية في الواجهة العامة لمكتبتك لأنها يمكن أن تسبب الكثير من المشكلات للعميل.

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

هناك مشكلة أخرى يمكن أن تواجهها وهي أن برامج التحويل البرمجي المختلفة لـ c++ يمكنها تشويه نفس الرموز بشكل مختلف مما يعني أنك قد تحتاج إلى توفير مكتبة منفصلة لكل مترجم تريد دعمه حتى لو كانوا يستخدمون نفس إصدار Boost.راجع كتاب "Imperfect C++" لمناقشة هذا الأمر.

في العالم الحالي الذي يضم مترجمات وبيئات مختلفة لـ C++، أعتقد أن الحقيقة المحزنة هي أنه يجب عليك تجنب وجود أي شيء غير لغة C في واجهتك والتأكد من ربط مكتبتك ديناميكيًا (لتجنب التعارضات عند ربط عملائك بمكتبتك ومكتبة وقت تشغيل Windows يمكن أن يكون الألم الحقيقي هنا).لا يزال بإمكانك استخدام التعزيز وبقدر ما تريد من لغة c++ الفاخرة داخل مكتبتك كما تريد حيث سيتم عزل جميع الرموز الخاصة بك عن بيئة عملائك في ملف dll.

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

ميزة أخرى لطيفة هي أنه من الأسهل عمومًا استدعاء وظائف C في ملف dll بدلاً من استدعاء وظائف c++ مع تغيير الأسماء الغريب إذا كنت تريد تعريض مكتبتك للغات أخرى غير C/C++.

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

هذا هو C++.كما تعلم، يمكنك قالب فئة الواجهة عبر تطبيق المؤشر المشترك.

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

إذا كنت تستخدم المؤشرات الأولية، فإنك تسمح بكل أنواع الاحتمالات.يمكن لرمز المستخدم استخدام مؤشر أولي، أو تخزينه في std::auto_ptr، أو Shared_ptr (سواء كان Boost أو TR1)، أو نسخته المنزلية من المؤشر الذكي.ولكن هذا قد يؤدي أيضًا إلى وقوع المستخدم في مشكلة إذا نسي تحرير الذاكرة، ويتطلب المزيد من التعليمات البرمجية في جانبه إذا كان يريد فقط إنشاء مؤقت لاستدعاء الأسلوب (إذا قدمت مؤشرات أولية، فسيتعين عليه تخزين مؤشر في متغير مؤشر غير مؤقت [ربما ذكي]).

الآن، إذا كنت تستخدم مؤشرًا ذكيًا، فإنك تفرض الحل على المستخدم.إذا كانوا يخططون لاستخدام نسختهم الخاصة من المؤشر الذكي (لنفترض أنك تستخدم Boost::shared_ptr ويريدون std::tr1::shared_ptr) فلن يُسمح لهم بعد الآن باستخدامه إذا كانوا يعملون مع واجهتك.مهما كان المؤشر الذكي الذي تقرره (إلى جانب std::auto_ptr المميز) فإنك لا تفرض حلاً فحسب، بل أيضًا المشكلات التي يواجهها.

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

كملاحظة جانبية، Boost::shared_ptr (boost 1.33+) هو الخيط آمن في معظم الحالات، ويستخدم تطبيقًا خاليًا من القفل في العديد من الأنظمة الأساسية.على أي حال، يجب أن يعطيك هذا فكرة عن الأشياء التي يجب عليك مراعاتها.

أخيرًا، يجب أن تأخذ في الاعتبار أنك لا تلزم المستخدم باستخدام نوع المؤشر الذكي الخاص بك فحسب، بل أيضًا نفس الإصدار منه.إذا قمت بتجميع lib الخاص بك مقابل إصدار معين من Boost، فسيكون المستخدم مرتبطًا بهذا التنفيذ المحدد o

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

يؤدي تقديم Boost::shared_ptr إلى إجبار عميلك على استخدام Boost.بالنسبة لبعض الناس، هذه مسألة ثانوية.

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

يستخدم auto_ptr أو التمسك بواجهة C.دائمًا ما يكون فرض استخدام C++ libs على واجهتك أمرًا قبيحًا، ويقضي على أي فرصة للتواجد عبر الأنظمة الأساسية، ويسبب كابوسًا للصيانة للعملاء الذين لديهم تكوينات "مصب" مختلفة.

بمجرد أن يصبح C++0x سائدًا بدرجة كافية لعملائك، قم بالتبديل إلى std::shared_ptr.

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