c++ - هل يتم تخزين deleter Shared_ptr في الذاكرة المخصصة بواسطة مخصص مخصص؟




language-lawyer c++17 (2)

util.smartptr.shared.const / 9 في الإصدار C ++ 11:

التأثيرات: إنشاء كائن Shared_ptr يمتلك الكائن p و deleter d. يستخدم المنشئان الثاني والرابع نسخة من a لتخصيص الذاكرة للاستخدام الداخلي.

البنائين الثاني والرابع لديهم هذه النماذج:

template<class Y, class D, class A> shared_ptr(Y* p, D d, A a);
template<class D, class A> shared_ptr(nullptr_t p, D d, A a);

في المسودة الأخيرة ، يكون util.smartptr.shared.const / 10 مكافئًا لغرضنا:

التأثيرات: إنشاء كائن Shared_ptr يمتلك الكائن p و deleter d. عندما لا يكون T نوع صفيف ، يقوم المنشئان الأول والثاني بتمكين Shared_from_this باستخدام p. يستخدم المنشئان الثاني والرابع نسخة من a لتخصيص الذاكرة للاستخدام الداخلي. إذا تم طرح استثناء ، يتم استدعاء d (p).

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

  • على الرغم من أن واجهة shared_ptr قد صُممت للسماح بالتنفيذ حيث لا توجد أبدًا كتلة تحكم ولكن تم وضع جميع weak_ptr في قائمة مرتبطة ، في الممارسة العملية لا يوجد مثل هذا التنفيذ والصياغة التي تم تعديلها على افتراض أن use_count هو شيء مشترك.

  • مطلوب deleter أن تتحرك فقط البناء. وبالتالي ، لا يمكن أن يكون لديك عدة نسخ في shared_ptr .

قد يكون من الممكن تخيل تنفيذ يضع deleter في ملف تصميم مشترك خاص ونقله عندما يتم حذف shared_ptr الخاص يبدو مطابقًا ، لكنه سيكون غريبًا حقًا ، خاصة وأن كتلة التحكم ربما تكون مطلوبة لعد الاستخدام ( ربما يكون ذلك ممكنًا ولكن حتى أغرب في فعل الشيء نفسه مع استخدام العد).

وجدت DRs ذات الصلة: 545 ، 575 ، 2434 (التي تقر بأن جميع التطبيقات تستخدم كتلة تحكم ويبدو أنها تشير إلى أن قيود الترابط المتعددة تنص عليها إلى حد ما) ، 2802 (والتي تجعل الشرط على الحامل يتحرك فقط قابل للبناء وبالتالي يمنع تطبيق حيث يتم نسخ deleter بين عدة shared_ptr ).

لنفترض أن لدي shared_ptr مع مخصص مخصص وحذف مخصص.

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

هل هذا غير محدد أم أنا فقط في عداد المفقودين شيء؟


أعتقد أن هذا غير محدد.

إليك كيفية تحديد [util.smartptr.shared.const]/10 ذات الصلة: [util.smartptr.shared.const]/10

template<class Y, class D> shared_ptr(Y* p, D d);
template<class Y, class D, class A> shared_ptr(Y* p, D d, A a);
template <class D> shared_ptr(nullptr_t p, D d);
template <class D, class A> shared_ptr(nullptr_t p, D d, A a);

التأثيرات: إنشاء كائن shared_ptr يمتلك الكائن p و deleter d . عندما لا يكون T نوع صفيف ، يقوم shared_from_this الأول والثاني بتمكين shared_from_this باستخدام p . يستخدم المنشئان الثاني والرابع نسخة من a لتخصيص الذاكرة للاستخدام الداخلي . إذا تم طرح استثناء ، يتم استدعاء d(p) .

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

template <typename T>
class shared_ptr : /* ... */ {
    // ...
    std::aligned_storage<16> _Small_deleter;
    // ...
public:
    // ...
    template <class _D, class _A>
    shared_ptr(nullptr_t, _D __d, _A __a) // for example
        : _Allocator_base{__a}
    {
        if constexpr (sizeof(_D) <= 16)
            _Construct_at(&_Small_deleter, __d);
        else
            // use 'a' to allocate storage for the deleter
    }
};

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





allocator