C++ Shared_ptr مقابل.Unique_ptr لإدارة الموارد
-
21-12-2019 - |
سؤال
لقد كنت أفكر في استخدام unique_ptr
ضد shared_ptr
ضد own_solution
.لقد استبعدت الخيار الأخير لأنني سأخطئ بالتأكيد، لكن لدي مشكلة مع كليهما unique_ptr
و shared_ptr
حيث لا يلتقط أي منهما بالضبط ما أريد.أرغب في إنشاء مدير موارد يمتلك موردًا بشكل صريح، ولكنني أرغب في أن يقوم مدير الموارد أيضًا بتوزيع مراجع للمورد.
إذا كنت تستخدم unique_ptr
في مدير الموارد وتوزيع المؤشرات الأولية، هناك احتمال أن يتمكنوا من الهروب إلى مكان آخر (على الرغم من أن هذا سيكون مخالفًا لـ "عقد" الفصل الذي أفترضه).إذا كنت تستخدم shared_ptr
وتسليمها weak_ptr
, ، لا يوجد ما يمنع المتصل من تحويل weak_ptr
إلى أ shared_ptr
وتخزين ذلك، وبالتالي من المحتمل إنشاء دورة أو ما هو أسوأ من ذلك، مورد يعيش بعد عمر مدير المورد.لذا أعتقد أن ما أبحث عنه هو أمر قابل للتأجيل weak_ptr
التي لا يمكن تحويلها إلى shared_ptr
.
أم أنني أتطلع فقط إلى تنفيذ العقد ببعض التعليقات شديدة اللهجة في الكود؟
شكرا على أية أفكار قد تكون لديكم حول هذا الموضوع.
المحلول
المؤشرات الذكية مثل shared_ptr
و unique_ptr
هي أدوات جيدة عندما يكون لديك امتلاك مؤشرات.
ولكن بالنسبة للمؤشرات غير المالكة، أي. مراقبة المؤشرات, ، فإن استخدام مؤشر خام أمر جيد.
في تصميمك، أعتقد أن مدير الموارد هو "المالك" الوحيد للموارد، لذلك يمكنك ببساطة الحصول على شكل من أشكال المؤشر الذكي داخل مدير الموارد.على سبيل المثال، يمكن أن يكون لدى مدير الموارد ملف std::vector<std::unique_ptr<Resource>>
كعضو بيانات، أو حتى أبسط std::vector<Resource>
إذا كان لديك Resource
تم تصميم الفئة لتكون قابلة للتخزين بشكل صحيح في ملف std::vector
.
بعد ذلك، يمكن لمدير الموارد أن يعطي للخارج فقط مؤشرات مراقبة غير مملوكة، والمؤشرات الأولية (أو مراجع C++) مناسبة لهذه الحالة.
بالطبع، من المهم أن يتجاوز عمر مدير الموارد عمر "عملاء الموارد".
نصائح أخرى
في النهاية، لا يمكنك إجبار أي شخص على الاستماع.اسأل Microsoft أو Apple أو أي مطور مكتبة مفتوحة المصدر، فجميعهم يعرفون تلك الأغنية.التعليق بالكلمات والأماكن المناسبة هو أفضل رهان لك.
تجنب إنشاء فئة المؤشر الذكي الخاصة بك، فهي تعيق التركيب وتقلل من سهولة القراءة.كملاذ أخير، حاول البحث في Boost، أو أي إطار عمل يجب أن تعمل معه التعليمات البرمجية الخاصة بك بالفعل.
إذا لم يكن لديك مالكين، فيمكن اختيارهم للاحتفاظ بهم weak_ptr
s أو (إذا كان مضمونًا أن يبقى صالحًا طوال المدة) المؤشرات الأولية.
إذا كنت تستخدم shared_ptr
داخليًا (لماذا يجب عليك ذلك)، من الأفضل تقديمه weak_ptr
والمؤشرات الخام.
تشير كل هذه المؤشرات الذكية بوضوح إلى سياسة الملكية.تشير المؤشرات الأولية إلى عدم الملكية أو عدم الملكية.
auto_ptr
:لا تستخدم، إهمال مع الكثير من الفخاخ حتى بالنسبة للحذرين.unique_ptr
:الملكية الوحيدة.shared_ptr
:ملكية مشتركةweak_ptr
:لا توجد ملكية، قد يتم حذفها خلف ظهرك.- المؤشر الخام
- صراحة لا توجد ملكية مع ضمان عمر أكبر
- أو إدارة الملكية اليدوية.
لذلك أفترض أن ما أبحث عنه هو ضعيف قابلة للتغيير لا يمكن تحويله إلى مشترك.
يمكنك توزيع فصلك المساعد الصغير:
template<typename T>
class NonConvertibleWeakPtr
{
public:
NonConvertibleWeakPtr(const std::shared_ptr<T>& p) : p_(p) {}
... // other constructors / assignment operators
bool expired() const { return p_.expired(); }
T* operator->() const { return get(); }
T& operator*() const { return *get(); }
private:
T* get() const { return p_.lock().get(); }
private:
std::weak_ptr<T> p_;
};
وهذا أفضل قليلًا من المؤشر الخام، لأنه يمكنك التحقق مما إذا كان المؤشر لا يزال صالحًا.
مثال على الاستخدام:
std::shared_ptr<int> sp = std::make_shared<int>(5);
{
NonConvertibleWeakPtr<int> wp(sp);
if(!wp.expired()) {
std::cout << *wp << std::endl;
}
}
ومع ذلك، لا يزال من الممكن للمستخدم إساءة استخدامه على سبيل المثال مع std::shared_ptr<T> blah(&(*wp));
, ، لكن الأمر يتطلب المزيد من الطاقة الإجرامية.