c++ - कस्टम आवंटनकर्ता द्वारा आबंटित स्मृति में एक साझा_प्राथर डिलेटर संग्रहीत है?




language-lawyer c++17 (2)

C ++ 11 में use.smartptr.saring.const / 9:

प्रभाव: एक साझा_प्रोट ऑब्जेक्ट का निर्माण करता है जो ऑब्जेक्ट पी और डीलेटर डी का मालिक है। दूसरे और चौथे निर्माणकर्ता आंतरिक उपयोग के लिए मेमोरी आवंटित करने के लिए एक की एक प्रति का उपयोग करेंगे।

दूसरे और चौथे निर्माणकर्ताओं के पास ये प्रोटोटाइप हैं:

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);

नवीनतम मसौदे में, .smartptr.saring.const / 10 हमारे उद्देश्य के बराबर है:

प्रभाव: एक साझा_प्रोट ऑब्जेक्ट का निर्माण करता है जो ऑब्जेक्ट पी और डीलेटर डी का मालिक है। जब T एक प्रकार का सरणी नहीं है, तो पहले और दूसरे निर्माणकर्ता p के साथ साझा_फ्रेम_थिस को सक्षम करते हैं। दूसरे और चौथे निर्माणकर्ता आंतरिक उपयोग के लिए मेमोरी आवंटित करने के लिए एक की एक प्रति का उपयोग करेंगे। यदि एक अपवाद को फेंक दिया जाता है, तो d (p) कहा जाता है।

तो आवंटितकर्ता का उपयोग किया जाता है यदि आवंटित मेमोरी में इसे आवंटित करने की आवश्यकता होती है। मानक की वर्तमान स्थिति और प्रासंगिक दोष रिपोर्टों को देखते हुए, यह अनिवार्य नहीं है लेकिन समिति द्वारा मान लिया गया है।

  • हालाँकि shared_ptr के इंटरफ़ेस को एक कार्यान्वयन की अनुमति देने के लिए डिज़ाइन किया गया था जहाँ कभी नियंत्रण ब्लॉक नहीं होता है, लेकिन सभी weak_ptr और weak_ptr को एक लिंक्ड सूची में डाल दिया जाता है, व्यवहार में ऐसा कोई कार्यान्वयन नहीं है और उदाहरण के लिए यह मानते हुए संशोधित किया गया है कि use_count है कुछ साझा किया।

  • डिलेटर को केवल रचनात्मक रूप से स्थानांतरित करने के लिए आवश्यक है। इस प्रकार shared_ptr में कई प्रतियाँ होना संभव नहीं है।

एक कार्यान्वयन की कल्पना करना संभव होगा, जो डेलेटर को एक विशेष डिज़ाइन किए गए शेप_प्ट्र में डालते हैं और इसे तब स्थानांतरित करते हैं जब यह विशेष shared_ptr गए हटाए गए अनुरूप प्रतीत होता है, लेकिन वास्तव में अजीब होगा, विशेष रूप से उपयोग ब्लॉक के लिए एक नियंत्रण ब्लॉक की आवश्यकता होती है (यह शायद संभव है, लेकिन यहां तक ​​कि उपयोग की गणना के साथ एक ही काम करने के लिए weirder)।

प्रासंगिक डीआर मैंने पाया: 545 , 575 , 2434 (जो यह स्वीकार करते हैं कि सभी कार्यान्वयन एक नियंत्रण ब्लॉक का उपयोग कर रहे हैं और इसका अर्थ यह लगता है कि बहु-सूत्रण कुछ हद तक इसे बाधित करता है), 2802 (जो कि निर्जलीकरण पर आवश्यकता को केवल रचनात्मक रूप से आगे बढ़ाते हैं और इस तरह रोकते हैं कार्यान्वयन जहां कई shared_ptr बीच डेलीटर की प्रतिलिपि बनाई गई है)।

कहें कि मेरे पास कस्टम आवंटनकर्ता और कस्टम shared_ptr साथ shared_ptr किया गया एक शेयर है।

मुझे मानक में ऐसा कुछ भी नहीं मिला जो इस बारे में बात करता हो कि डिलेटर को कहां संग्रहीत किया जाना चाहिए: यह नहीं कहता है कि कस्टम एलोलेटर का उपयोग डेलेटर की मेमोरी के लिए किया जाएगा, और यह नहीं कहता है कि यह नहीं होगा।

क्या यह अनिर्दिष्ट है या मैं सिर्फ कुछ याद कर रहा हूं?


मेरा मानना ​​है कि यह अनिर्दिष्ट है।

यहां बताया गया है कि संबंधित निर्माणकर्ता कैसे निर्दिष्ट किए जाते हैं: [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 और डीलेटर d का मालिक है। जब T एक प्रकार का सरणी नहीं है, तो पहले और दूसरे निर्माणकर्ता p साथ shared_from_this को सक्षम shared_from_this । दूसरे और चौथे निर्माणकर्ता आंतरिक उपयोग के लिए मेमोरी आवंटित करने के लिए एक की एक प्रति का उपयोग करेंगे । यदि एक अपवाद को फेंक दिया जाता है, तो d(p) कहा जाता है।

अब, मेरी व्याख्या यह है कि जब कार्यान्वयन को आंतरिक उपयोग के लिए मेमोरी की आवश्यकता होती है, तो यह a का उपयोग करके ऐसा करता 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
    }
};

क्या यह कार्यान्वयन "आंतरिक उपयोग के लिए मेमोरी आवंटित करने के लिए एक की एक प्रति" का उपयोग करता है? हाँ यह करता है। यह कभी भी स्मृति को आवंटित नहीं करता है सिवाय a का उपयोग करके। इस भोले-भाले कार्यान्वयन के साथ कई समस्याएं हैं, लेकिन हम कहते हैं कि यह आवंटनकर्ताओं का उपयोग करने के लिए स्विच करता है लेकिन सबसे सरल मामला है जिसमें shared_ptr सीधे एक पॉइंटर से निर्मित होता है और इसे कभी भी कॉपी या स्थानांतरित या अन्यथा संदर्भित नहीं किया जाता है और कोई अन्य जटिलताएं नहीं होती हैं। मुद्दा यह है, सिर्फ इसलिए कि हम एक वैध कार्यान्वयन की कल्पना करने में विफल हैं इसका मतलब यह नहीं है कि यह सैद्धांतिक रूप से मौजूद है। मैं यह नहीं कह रहा हूं कि ऐसा कार्यान्वयन वास्तव में पाया जा सकता है, बस यह मानक सक्रिय रूप से इसे प्रतिबंधित नहीं करता है।





allocator