2012-03-18 13 views
5

क्या लाइब्रेरी में std::uninitialized_fill() के साथ मेमोरी प्रारंभ करने के लिए यह समझ में आता है जब उपयोगकर्ता द्वारा तर्क के रूप में पारित आवंटन को स्मृति प्राप्त करने के लिए उपयोग किया जाता है? मैं यह पूछता हूं क्योंकि एक आवंटक ने अपनी construct() विधि (allocate() विधि के अलावा) प्रदान की है, जिसका कार्यान्वयन मानक से अलग हो सकता है, इसलिए शायद std::uninitialized_fill() सभी मामलों में हमेशा उपयुक्त नहीं है।क्या किसी भी आवंटक के साथ std :: uninitialized_fill() का उपयोग करना समझ में आता है?

सटीक होने के लिए, मेरे संदेह Stroustrup (परिशिष्ट ई "मानक-पुस्तकालय अपवाद सुरक्षा", अनुभाग ई 3.1 द्वारा लिखित सी ++ पुस्तक से आते हैं, जिसमें लेखक template<class T, class A> vector<T,A>::vector(size_type n, const T& val, const A& a) का संभावित कार्यान्वयन देता है: आवंटक वेक्टर के लिए स्मृति प्राप्त करने के लिए प्रयोग किया जाता है, तो std::uninitialized_fill() प्राप्त स्मृति को प्रारंभ करने के लिए उपयोग किया जाता है।

उन्होंने यह भी std::uninitialized_fill() के कार्यान्वयन, जो आंतरिक रूप से मानक नियुक्ति स्मृति को प्रारंभ करने के लिए नए का उपयोग करता है देता है, लेकिन संभाजक वेक्टर निर्माता के लिए तर्क के रूप में पारित कर दिया की construct() विधि का नहीं रह सबूत नहीं है।

+1

'एसटीडी क्या है :: initialize_fill() '? क्या आपका मतलब है 'std :: uninitialized_fill() '? 'Initialize_fill()' समारोह अप सी ++ मानक में कहीं भी दिखाई नहीं है, 'uninitialized_fill के विपरीत()'। –

+0

@Insilico क्षमा करें, यह एक टाइपो था। धन्यवाद। मैंने सवाल तय किया। – Martin

+2

यह मेरे प्रश्न से संबंधित प्रतीत होता है: http://stackoverflow.com/questions/9727556/is-uninitialized-copy-fillin-first-in-last-for-dest-aa-an-oversight-in-th, मैं करता हूं लगता है कि वास्तविकता में सामान्य 'uninitialized_fill' –

उत्तर

2

मैं वेक्टर के जीसीसी कार्यान्वयन की जाँच की, इसे पढ़ता है:

vector(size_type __n, const value_type& __value, 
     const allocator_type& __a = allocator_type()) 
    : _Base(__n, __a) 
    { _M_fill_initialize(__n, __value); } 

    ... 

    _M_fill_initialize(size_type __n, const value_type& __value) 
    { 
    this->_M_impl._M_finish = 
     std::__uninitialized_fill_n_a(this->_M_impl._M_start, __n, __value, 
            _M_get_Tp_allocator()); 
    } 

इसलिए, यह की तरह संभाजक की जानकारी नहीं होती लग रहा है। हालांकि uninitialized_fill_n_a का कोड अजीब है, इसमें दो ओवरलोड हैं (नीचे देखें), जेनेरिक आवंटक के लिए एक और दूसरा std::allocator के लिए।

जेनेरिक कॉल, construct और std::allocator के लिए विशेष बस std::uninitialized_fill() पर कॉल करता है।

तो, मेरे निष्कर्ष निम्नलिखित,

1) सभी std::allocator के construct नई नियुक्ति और

2 के रूप में एक ही प्रभाव है) कि जेनेरिक allocators के लिए नहीं माना जा सकता, या कम से कम जीसीसी है std::vector यह नहीं मानता है। (@Michael बर के अनुसार आप इस में सी ++ 03 मान सकते हैं, दुर्भाग्य से वह सी ++ 11 का उल्लेख नहीं है)।

इसलिए निर्माण का उपयोग करें (कि std::allocator_traits<Alloc>::construct(alloc, pointer, value) है)।

मेरे व्यक्तिगत राय (इस जांच के बाद), कि

i) std::uninitialized_fill दोषपूर्ण है, में है कि के रूप में संभाजक के साथ एक आखिरी वैकल्पिक तर्क (या किसी अन्य अधिभार),

ii) ले जाना चाहिए एक समाधान अपने क्रियान्वयन विस्तार के अंदर आप एक .uninitialized_fill(first, last, value, alloc) समारोह है कि (कैसे निर्माणों विफलता पर नष्ट कर देता है साथ unrolled कर रहे हैं नीचे टिप्पणी) अपवादों में से निपटने सहित काम करता है, होना चाहिए। ।

iii) आप संभाजक बारे में जानकारी है (और मूल रूप से आप इसे reimplement करने के लिए है जब वर्तमान std::unitialized_fill बहुत बेकार है)


अब कोड ऊपर संदर्भित:

template<typename _ForwardIterator, typename _Size, typename _Tp, 
      typename _Allocator> 
    _ForwardIterator 
    __uninitialized_fill_n_a(_ForwardIterator __first, _Size __n, 
          const _Tp& __x, _Allocator& __alloc) 
    { 
     _ForwardIterator __cur = __first; 
     __try 
     { 
      typedef __gnu_cxx::__alloc_traits<_Allocator> __traits; 
      for (; __n > 0; --__n, ++__cur) 
      __traits::construct(__alloc, std::__addressof(*__cur), __x); 
      return __cur; 
     } 
     __catch(...) 
     { 
      std::_Destroy(__first, __cur, __alloc); 
      __throw_exception_again; 
     } 
    } 

    template<typename _ForwardIterator, typename _Size, typename _Tp, 
      typename _Tp2> 
    inline _ForwardIterator 
    __uninitialized_fill_n_a(_ForwardIterator __first, _Size __n, 
          const _Tp& __x, allocator<_Tp2>&) 
    { return std::uninitialized_fill_n(__first, __n, __x); } 
0

किसी भी गैर-डिफ़ॉल्ट आवंटक के construct() फ़ंक्शन के कार्यान्वयन के लिए एक प्लेसमेंट का प्रभाव होना आवश्यक है (प्रति तालिका 32 - सी ++ 03 में आवंटन आवश्यकताओं)।

तो std::uninitialized_fill() (जिसे सीमा में प्रत्येक तत्व पर नया प्लेसमेंट करने के रूप में परिभाषित किया गया है) का उपयोग करना ठीक होना चाहिए - भले ही कस्टम आवंटक का उपयोग किया जाए।

+2

मुझे लगता है कि वह पूछ रहा है कि 'uninitialized_fill' के साथ कॉल को 'निर्माण' में बदलना ठीक है, जो अलग है। 'निर्माण' की आवश्यकता से परे अतिरिक्त प्रभाव हो सकते हैं। – Potatoswatter

1

मैं construct पर कॉल करूंगा।

कस्टम आवंटक प्रदान करने के कई कारण हैं, और बेहतर आवंटन नीति (पूल/स्टैक स्टोरेज का उपयोग करके) एकमात्र नहीं है।

मैंने कस्टम कंटेनर में गलत आवंटकों के उपयोग को ट्रैक करने में मदद करने के लिए डिबगिंग आवंटकों को भी (और डबल्ड किया) देखा है। स्मृति उपयोग को ट्रैक करने, आंकड़ों को इकट्ठा करने, आदि के लिए आवंटकों का उपयोग करना भी संभव है ...

इस प्रकार, construct वस्तु (या नहीं) के ऑब्जेक्ट के निर्माण से परे अतिरिक्त प्रभाव हो सकता है, और इस प्रकार यह आवश्यक नहीं है सरल प्लेसमेंट new

मेरी डिबगिंग संभाजक में, construct कि पता पर बुलाया बिना destroy कॉल करने से पहले एक त्रुटि थी (और इसी तरह destroy बुलाया बिना स्मृति सुधारने), तो कम से कम मैं सुसंगत और जोड़ी construct जा रहा है destroy और प्लेसमेंट के साथ की सिफारिश करेंगे एक स्पष्ट विनाशक कॉल के साथ new

+0

'नष्ट', 'विनाश' नहीं (फ्रेंच में विपरीत, इस बार कुछ बार काट दिया गया है, यह असममित है :)। –

+0

@AlexandreC .: धन्यवाद, कि मैं जाँच नहीं करने के लिए क्या मिलता है ... –

संबंधित मुद्दे

 संबंधित मुद्दे