2009-10-19 7 views
6

मैं निम्न-स्तरीय एपीआई के साथ काम कर रहा हूं जो क्रमशः एक स्ट्रिंग और इसकी लंबाई का प्रतिनिधित्व करने के लिए char* और संख्यात्मक मान स्वीकार करता है। मेरा कोड std::basic_string का उपयोग करता है और उचित अनुवाद के साथ इन विधियों में कॉल करता है। दुर्भाग्यवश, इनमें से कई विधियां अलग-अलग आकार की स्ट्रिंग लम्बाई स्वीकार करती हैं (यानी अधिकतम (unsigned char), अधिकतम (short), आदि ...) और मैं यह सुनिश्चित करने के लिए कोड लिख रहा हूं कि मेरी स्ट्रिंग इंस्टेंस निर्धारित अधिकतम लंबाई से अधिक न हो निम्न स्तर के एपीआई द्वारा।कोई लंबाई सीमा वाले स्ट्रिंग को लागू करने के लिए std :: basic_string का लाभ उठा सकता है?

डिफ़ॉल्ट रूप से, एक std::basic_string उदाहरण की अधिकतम लंबाई का अधिकतम मान से बाध्य है size_t (या तो अधिकतम (unsigned int) या अधिकतम (__int64))। std::basic_string कार्यान्वयन के गुणों और आवंटन कार्यान्वयन में हेरफेर करने का कोई तरीका है ताकि मैं size_t के स्थान पर उपयोग करने के लिए अपना स्वयं का प्रकार निर्दिष्ट कर सकूं? ऐसा करके, मैं std::basic_string कार्यान्वयन के भीतर किसी भी मौजूदा सीमा शुल्क का लाभ उठाने की उम्मीद कर रहा हूं इसलिए अनुवाद करने के दौरान मुझे ऐसा करने की ज़रूरत नहीं है।

मेरे प्रारंभिक जांच से पता चलता है कि यह मेरी अपनी स्ट्रिंग वर्ग लेखन के बिना संभव नहीं है, लेकिन मैं आशा करती हूं कि मैं माता पिता के रूप में कुछ :)

उत्तर

5

आप std::basic_string पर एक कस्टम आवंटक पास कर सकते हैं जिसमें आपके इच्छित आकार का अधिकतम आकार हो। यह पर्याप्त होना चाहिए। इस तरह शायद कुछ:

template <class T> 
class my_allocator { 
public: 
    typedef T    value_type; 

    typedef std::size_t size_type; 
    typedef std::ptrdiff_t difference_type; 
    typedef T*    pointer; 
    typedef const T*  const_pointer; 
    typedef T&    reference; 
    typedef const T&  const_reference; 

    pointer address(reference r) const    { return &r; } 
    const_pointer address(const_reference r) const { return &r; } 

    my_allocator() throw() {} 

    template <class U> 
    my_allocator(const my_allocator<U>&) throw() {} 

    ~my_allocator() throw() {} 

    pointer allocate(size_type n, void * = 0) { 
     // fail if we try to allocate too much 
     if((n * sizeof(T))> max_size()) { throw std::bad_alloc(); } 
     return static_cast<T *>(::operator new(n * sizeof(T))); 
    } 

    void deallocate(pointer p, size_type) { 
     return ::operator delete(p); 
    } 

    void construct(pointer p, const T& val) { new(p) T(val); } 
    void destroy(pointer p)     { p->~T(); } 

    // max out at about 64k 
    size_type max_size() const throw() { return 0xffff; } 

    template <class U> 
    struct rebind { typedef my_allocator<U> other; }; 

    template <class U> 
    my_allocator& operator=(const my_allocator<U> &rhs) { 
     (void)rhs; 
     return *this; 
    } 
}; 

तो फिर तुम शायद यह कर सकते हैं:

typedef std::basic_string<char, std::char_traits<char>, my_allocator<char> > limited_string; 

संपादित करें: मैं सिर्फ यकीन है कि यह काम करता है के रूप में उम्मीद करने के लिए एक परीक्षण किया है। निम्नलिखित कोड इसका परीक्षण करता है।

int main() { 
    limited_string s; 
    s = "AAAA"; 
    s += s; 
    s += s; 
    s += s; 
    s += s; 
    s += s; 
    s += s; 
    s += s; // 512 chars... 
    s += s; 
    s += s; 
    s += s; 
    s += s; 
    s += s; 
    s += s; // 32768 chars... 
    s += s; // this will throw std::bad_alloc 

    std::cout << s.max_size() << std::endl; 
    std::cout << s.size() << std::endl; 
} 

कि पिछले s += s शीर्ष पर डाल दिया है और एक std::bad_alloc अपवाद का कारण होगा, (के बाद से मेरी सीमा 64k से कम है)। दुर्भाग्यवश जीसीसी का std::basic_string::max_size() कार्यान्वयन आपके द्वारा उपयोग किए जाने वाले आवंटन पर इसके परिणाम का आधार नहीं बनाता है, इसलिए यह अभी भी अधिक आवंटित करने में सक्षम होने का दावा करेगा। (मुझे यकीन नहीं है कि यह एक बग है या नहीं ...)।

लेकिन यह निश्चित रूप से आपको तारों के आकारों पर सरल तरीके से हार्ड सीमा लगाएगा। आप अधिकतम आकार को टेम्पलेट पैरामीटर भी बना सकते हैं ताकि आपको केवल आवंटक के लिए कोड लिखना पड़े।

+1

मैं एक इंटेल टेम्पलेट पैरामीटर जोड़ा होगा और max_size() वापसी एन था; तो वह typedef std :: basic_string , my_allocator > my256string कर सकता है; – jmucchiello

+0

मुझे लगता है कि टेम्पलेट तर्क के रूप में 'size_type' को उजागर करना फायदेमंद होगा क्योंकि उपयोगकर्ता यह चुनने के लिए स्वतंत्र है कि कौन सा' size_type' किसी दिए गए स्ट्रिंग उदाहरण के लिए सबसे उपयुक्त है। फिर, आंशिक टेम्पलेट विशेषज्ञता इस प्रकार को 'basic_string' के साथ अच्छा बनाने में मदद करेगी। –

0

आप एसटीडी के साथ एक वर्ग नहीं बनाई जा सकती :: स्ट्रिंग अनदेखी की और over_ide c_str()? या अपने स्वयं के c_str16(), c_str32(), आदि को परिभाषित करें और वहां अनुवाद लागू करें?

+2

मानक पुस्तकालय में से अधिकांश से विरासत में मिला जा करने के लिए इरादा नहीं है (उनके पास कोई आभासी तरीका नहीं है)। तो यह सलाह नहीं है। –

4

मैं इवान टेरन से उनके समाधान के बारे में सहमत हूं। यह सिर्फ उनके समाधान के संशोधन से अधिक नहीं है:

template <typename Type, typename std::allocator<Type>::size_type maxSize> 
struct myalloc : std::allocator<Type> 
{ 
    // hide std::allocator[ max_size() & allocate(...) ] 

    std::allocator<Type>::size_type max_size() const throw() 
    { 
     return maxSize; 
    } 
    std::allocator<Type>::pointer allocate 
     (std::allocator<Type>::size_type n, void * = 0) 
    { 
     // fail if we try to allocate too much 
     if((n * sizeof(Type))> max_size()) { throw std::bad_alloc(); } 
     return static_cast<Type *>(::operator new(n * sizeof(Type))); 
    } 
}; 

बारे में पता आप myalloc साथ बिल्कुल बहुरूपता उपयोग नहीं करना चाहिए है। तो यह विनाशकारी है:

// std::allocator doesn't have a virtual destructor 
std::allocator<char>* alloc = new myalloc<char>; 

के रूप में अगर यह एक अलग प्रकार है तुम बस के लिए इसका इस्तेमाल, यह निम्न मामले में सुरक्षित है:

myalloc<char, 1024> alloc; // max size == 1024 
+0

हाँ, मैंने बस अधिकतम आकार को टेम्पलेट पैरामीटर बनाने का विचार किया था। दुर्भाग्यवश, मुझे नहीं लगता कि आपका समाधान इस तरह काम करेगा। क्योंकि (कम से कम जीसीसी) स्ट्रिंग कार्यान्वयन आवंटक के अधिकतम आकार पर इसका अधिकतम आकार आधार नहीं बनाता है। तो मुझे 'max_size' बाइट्स से अधिक अनुरोध करने पर' आवंटित (...) 'फेंकना पड़ा। –

+0

@Evan आपका समाधान अच्छा है, आपको मेरा +1 बीटीडब्ल्यू मिला है। जैसा कि आपने स्पष्ट किया है, मैं 'आवंटित' के लिए और कोड जोड़ूंगा :) – AraK