जब मैं अपने कंटेनर के लिए कस्टम आवंटक का उपयोग करता हूं तो निम्न कोड मुझे अपेक्षित परिणाम देता है (आकार sz को वैश्विक चर के रूप में रखते हुए)

#include <cstddef> /* size_t */
#include <new> /* Only for bad_alloc */
#include <vector>
using std::vector;
#include <iostream>
using std::cout;
using std::endl;
std::size_t constexpr sz = 4;
template <typename T> class StaticAllocator {
protected:
    static T buf[sz];
public:
    typedef T value_type;
    T* allocate(std::size_t const n) {
        if (n > sz) throw std::bad_alloc();
        return buf;
    }
    void deallocate(T*, std::size_t) {}
};
template<typename T> T StaticAllocator<T>::buf[sz];
int main(void) {
    std::vector<char, StaticAllocator<char> > v;
    v.push_back('a');
    v.push_back('b');
    for (auto const& i : v) cout << i << endl;
}

जब मैं कक्षा के लिए टेम्पलेट पैरामीटर के रूप में आकार का उपयोग करने का प्रयास करता हूं तो कोड का यह संस्करण मुझे कंपाइलर त्रुटि देता है

#include <cstddef> /* size_t */
#include <new> /* bad_alloc */
#include <vector>
using std::vector;
#include <iostream>
using std::cout;
using std::endl;
template<typename T, std::size_t sz> class StaticAllocator {
protected:
    static T buf[sz];
public:
    typedef T value_type;
    T* allocate(std::size_t const n) {
        if (n > sz) throw std::bad_alloc();
        return buf;
    }
    void deallocate(T*, std::size_t) {}
};
template<typename T, std::size_t sz> T StaticAllocator<T, sz>::buf[sz];
int main(void) {
    std::vector<char, StaticAllocator<char, 4> > v;
    v.push_back('a');
    v.push_back('b');
    for (auto const& i : v) cout << i << endl;
}
c++
3
Ibrahim Quraish 5 जिंदा 2020, 09:04

1 उत्तर

सबसे बढ़िया उत्तर

T प्रकार के आवंटक से किसी प्रकार U के लिए आवंटनकर्ता प्राप्त करने के लिए, सदस्य उपनाम टेम्पलेट std::allocator_traits::rebind_alloc<U> का उपयोग किया जाता है [allocator.traits.types]:

Alloc::rebind<T>::other अगर Alloc::rebind<T>::other मान्य है और एक प्रकार को दर्शाता है; अन्यथा, Alloc<T, Args> यदि Alloc, Alloc<U, Args>, जहां Args शून्य या अधिक प्रकार के तर्क हैं, का एक वर्ग टेम्पलेट इंस्टेंटेशन है; अन्यथा, rebind_alloc का इंस्टेंटेशन गलत तरीके से बनता है।

ध्यान दें कि Args प्रकार टेम्प्लेट पैरामीटर हैं। आपके आवंटकों में कोई rebind नहीं है। पहले मामले में Alloc<U> का उपयोग किया जाता है, Args खाली है। लेकिन दूसरे मामले में, दूसरा टेम्प्लेट पैरामीटर एक गैर-प्रकार है, इसका मिलान Args से नहीं किया जा सकता है।

आपको मैन्युअल रूप से rebind सदस्य संरचना जोड़ने की आवश्यकता है:

template<typename T, std::size_t sz>
class StaticAllocator {
    // ...

    template<class U>
    struct rebind {
        using other = StaticAllocator<U, sz>;
    };
};

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


निम्नलिखित समाधान अब-हटाए गए उत्तर में प्रस्तावित किया गया था: std::allocator<T> से इनहेरिट करें:

template<typename T, std::size_t sz> class StaticAllocator : 
    public std::allocator<T> {
// ...
};

कोड संकलित और चलता है, लेकिन... StaticAllocator::allocate और StaticAllocator::deallocate को नहीं कहा जाता है (कम से कम libstdc++ में)। इसका कारण यह है कि आंतरिक रूप से std::vector हमेशा आवंटक प्रकार प्राप्त करने के लिए rebind का उपयोग करता है:

using Tp_alloc_type = 
    typename gnu_cxx::alloc_traits<Alloc>::template rebind<Tp>::other;

rebind को std::allocator<T> से इनहेरिट किया गया है और यह StaticAllocator के बजाय std::allocator लौटाता है। इसलिए आपको अभी भी अपना rebind StaticAllocator में देना होगा।

3
Evg 5 जिंदा 2020, 11:34