polymorphic_allocator: मुझे इसका उपयोग कब और क्यों करना चाहिए?


122

यहाँ cppreference पर प्रलेखन है , यहाँ काम करने का प्रारूप है।

मुझे यह स्वीकार करना चाहिए कि मुझे समझ नहीं आया कि इसका वास्तविक उद्देश्य क्या है polymorphic_allocatorऔर कब / क्यों / मुझे इसका उपयोग कैसे करना चाहिए।
एक उदाहरण के रूप pmr::vectorमें, निम्नलिखित हस्ताक्षर हैं:

namespace pmr {
    template <class T>
    using vector = std::vector<T, polymorphic_allocator<T>>;
}

क्या करता है polymorphic_allocatorऑफर? std::pmr::vectorपुराने जमाने के संबंध में क्या प्रस्ताव है std::vector? अब मैं क्या कर सकता हूं जो मैं अब तक नहीं कर पाया था?
उस आवंटनकर्ता का वास्तविक उद्देश्य क्या है और मुझे वास्तव में इसका उपयोग कब करना चाहिए?


1
वे allocator<T>स्वाभाविक रूप से कुछ समस्याओं को दूर करने की कोशिश करते हैं । यदि आप बार-बार आवंटन का उपयोग करते हैं तो आपको इसमें मान दिखाई देगा।
edmz

2
प्रासंगिक कागज
edmz

जवाबों:


103

Cppreference से च्वाइस कोट:

यह रनटाइम बहुरूपता वस्तुओं को पॉलीमोर्फिक_लोकेटर का उपयोग करने की अनुमति देता है जैसे कि वे समान स्थिर आवंटनकर्ता प्रकार के बावजूद रन समय पर विभिन्न आवंटन प्रकार का उपयोग करते हैं।

"नियमित" आवंटनकर्ताओं के साथ मुद्दा यह है कि वे कंटेनर के प्रकार को बदलते हैं। यदि आप vectorएक विशिष्ट आवंटनकर्ता के साथ चाहते हैं , तो आप Allocatorटेम्पलेट पैरामीटर का उपयोग कर सकते हैं :

auto my_vector = std::vector<int,my_allocator>();

अब समस्या यह है कि यह वेक्टर एक वेक्टर के समान नहीं है जो एक अलग आवंटनकर्ता के साथ वेक्टर है। आप इसे एक ऐसे फंक्शन में नहीं भेज सकते जिसके लिए डिफॉल्ट-एलोकेटर वेक्टर की आवश्यकता होती है, उदाहरण के लिए, या एक ही वेरिएबल / पॉइंटर के लिए एक अलग एलोकेटर टाइप के साथ दो वैक्टर असाइन करें, जैसे:

auto my_vector = std::vector<int,my_allocator>();
auto my_vector2 = std::vector<int,other_allocator>();
auto vec = my_vector; // ok
vec = my_vector2; // error

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

आवंटनकर्ता व्यवहार का अनुकूलन आवंटनकर्ता को देकर किया जाता है std::memory_resource *:

// define allocation behaviour via a custom "memory_resource"
class my_memory_resource : public std::pmr::memory_resource { ... };
my_memory_resource mem_res;
auto my_vector = std::pmr::vector<int>(0, &mem_res);

// define a second memory resource
class other_memory_resource : public std::pmr::memory_resource { ... };
other_memory_resource mem_res_other;
auto my_other_vector = std::pmr::vector<int>(0, &mes_res_other);

auto vec = my_vector; // type is std::pmr::vector<int>
vec = my_other_vector; // this is ok -
      // my_vector and my_other_vector have same type

मुख्य शेष मुद्दा, जैसा कि मैं इसे देखता हूं, यह है कि एक std::pmr::कंटेनर अभी भी std::डिफ़ॉल्ट आवंटनकर्ता का उपयोग करके समकक्ष कंटेनर के साथ संगत नहीं है । आपको उस समय कुछ निर्णय लेने की आवश्यकता होती है जब आप एक इंटरफ़ेस डिज़ाइन करते हैं जो एक कंटेनर के साथ काम करता है:

  • क्या यह संभव है कि कंटेनर को कस्टम आवंटन की आवश्यकता हो?
  • यदि ऐसा है, तो क्या मुझे एक टेम्पलेट पैरामीटर जोड़ना चाहिए (मध्यस्थ आवंटन के लिए अनुमति देने के लिए) या क्या मुझे एक पॉलीमॉर्फिक आवंटनकर्ता के उपयोग को अनिवार्य करना चाहिए?

एक टेम्पलेट समाधान एक पॉलीमॉर्फिक आवंटनकर्ता सहित किसी भी आवंटनकर्ता के लिए अनुमति देता है , लेकिन इसमें अन्य कमियां हैं (उत्पन्न कोड आकार, संकलन समय, कोड को हेडर फ़ाइल में उजागर किया जाना चाहिए, आगे "प्रकार संदूषण" की संभावना है जो समस्या को बाहर की ओर धकेलती रहती है)। दूसरी ओर एक पॉलीमॉर्फिक आवंटन समाधान यह निर्धारित करता है कि एक पॉलीमॉर्फिक आवंटन का उपयोग किया जाना चाहिए। यह std::कंटेनर का उपयोग करने से रोकता है जो डिफ़ॉल्ट आवंटनकर्ता का उपयोग करता है, और विरासत कोड के साथ इंटरफेस के लिए निहितार्थ हो सकता है।

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


2
तो, std::pmr::कक्षाओं के लिए द्विआधारी लेआउट बहुत अलग होने की संभावना है?
यूरी पिनहोल

12
@EuriPinhollow आप नहीं कर सकते हैं reinterpret_castजो std::vector<X>और std::pmr::vector<X>, कि क्या आप पूछ रहे हैं।
davmac

4
ऐसे साधारण मामलों के लिए जिनमें मेमोरी संसाधन रनटाइम वैरिएबल पर निर्भर नहीं करता है, एक अच्छा कंपाइलर डिवर्टलाइज हो जाएगा और आप बिना किसी अतिरिक्त लागत के पॉलीमॉर्फिक एलोकेटर के साथ समाप्त हो जाएंगे (पॉइंटर को स्टोर करने के अलावा जो वास्तव में समस्या नहीं है)। मुझे लगा कि यह ध्यान देने योग्य है।
देईदेई

1
@ यक-आदमनेवरुमोंट "एक std::pmr::कंटेनर अभी भी std::डिफ़ॉल्ट आवंटनकर्ता का उपयोग कर समकक्ष कंटेनर के साथ संगत नहीं है " । कोई असाइनमेंट ऑपरेटर एक से दूसरे में परिभाषित नहीं है। जब संदेह हो, तो इसे आज़माएं: Godbolt.org/z/Q5BKev (कोड बिल्कुल ऊपर नहीं है क्योंकि gcc / clang में "प्रायोगिक" नामस्थान में बहुरूप आवंटन वर्ग हैं)।
davmac

1
@davmac आह, तो वहाँ एक template<class OtherA, std::enable_if< A can be constructed from OtherA > vector( vector<T, OtherA>&& )निर्माता नहीं है । मैं अनिश्चित था, और नहीं जानता था कि एक कंपाइलर कहां मिल सकता है जिसमें टीएस-कंप्लेंट पीटीआर था।
यक्क - एडम नेवरामॉन्ट

33

polymorphic_allocatorएक कस्टम एलोकेटर के रूप में std::functionहै जो एक प्रत्यक्ष फ़ंक्शन कॉल के लिए है।

यह केवल आपको अपने कंटेनर के साथ एक एलोकेटर का उपयोग करने की अनुमति देता है, बिना निर्णय के बिंदु पर, जो एक। इसलिए यदि आपके पास ऐसी स्थिति है जहां एक से अधिक आवंटनकर्ता उपयुक्त होंगे, तो आप उपयोग कर सकते हैं polymorphic_allocator

हो सकता है कि आप अपने इंटरफ़ेस को आसान बनाने के लिए किस एलोकेटर का उपयोग करना चाहते हैं, या हो सकता है कि आप इसे अलग-अलग मामलों के लिए स्वैप करना चाहते हों।

पहले आपको एक कोड की आवश्यकता होती है, जिसे एक एलोकेटर की आवश्यकता होती है, फिर आपको पीएआर वेक्टर पर विचार करने से पहले स्वैप करने में सक्षम होना चाहिए।


7

पॉलीमॉर्फिक आवंटनकर्ताओं का एक दोष यह है कि polymorphic_allocator<T>::pointerयह हमेशा ही होता है T*। इसका मतलब है कि आप उन्हें फैंसी पॉइंटर्स के साथ उपयोग नहीं कर सकते । यदि आप vectorसाझा मेमोरी में किसी स्थान के तत्वों की तरह कुछ करना चाहते हैं और उन्हें boost::interprocess::offset_ptrएस के माध्यम से एक्सेस करना चाहते हैं, तो आपको इसके लिए एक नियमित पुराने गैर-पॉलीमॉर्फिक आवंटनक का उपयोग करने की आवश्यकता है।

इसलिए, हालांकि पॉलीमॉर्फिक आवंटनकर्ता आपको कंटेनर के स्थिर प्रकार को बदलने के बिना आवंटन व्यवहार को बदलते हैं, वे सीमित करते हैं कि आवंटन क्या है।


2
यह एक महत्वपूर्ण बिंदु है और एक बड़ा बमर है। आर्थर ओ'डायर की ओर से सार्थक फैंसी पॉइंटर्स पेपर क्षेत्र की खोज करते हैं, जैसा कि उनकी पुस्तक "
मास्ट्रिंग

क्या आप पॉलीमॉर्फिक एलोकेटर का उपयोग करने के लिए वास्तविक दुनिया का उपयोग कर सकते हैं?
दरू
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.