2013-08-01 6 views
14

द्वारा मूल्य बनाम std एल्गोरिदम इटरेटर पैरामीटर पास करना मुझे आश्चर्य है कि क्यों एसटीएल में कई टेम्पलेट एल्गोरिदम में तर्क संदर्भ द्वारा पारित नहीं होते हैं बल्कि मूल्य के अनुसार।संदर्भ बनाम मूल्य

template<class InputIterator> 
typename iterator_traits<InputIterator>::difference_type 
distance (InputIterator first, InputIterator last); 

जब मैं इस समारोह के लिए दो iterators गुजरती हैं, वे कॉपी कर रहे हैं: यहाँ <iterator> हैडर से एक उदाहरण है। मेरे अनुभवहीन विचार हैं कि यह इटरेटर वस्तुओं को कॉपी से बचने के लिए स्थिरांक-संदर्भ द्वारा इन iterators पारित करने के लिए बेहतर होगा:

template<class InputIterator> 
typename iterator_traits<InputIterator>::difference_type 
distance (const InputIterator &first, const InputIterator &last); 

एक कह सकते हैं कि iterators सामान्य बहुत छोटी वस्तुओं में हैं और है कि उन्हें कॉपी करने महंगा नहीं है। लेकिन फिर भी: सस्ते प्रतिलिपि किसी भी प्रतिलिपि की तुलना में अधिक महंगी होगी।

तो एसटीएल-संस्करण में, इटेटर को मूल्य से पारित करने का क्या कारण है?

धन्यवाद!

+6

एक बात जो मेरे दिमाग में आती है और जो संदर्भ में 'constnessness के खिलाफ है: इटरेटर को उनका उपयोग करते समय संशोधित करने की आवश्यकता होती है। एक अन्य कार्यान्वयन विवरण *** *** हो सकता है कि इटरेटर वास्तव में पॉइंटर्स के रूप में लागू किए गए हैं। तो ज्यादातर मामलों में संदर्भ हैं। यदि आप पॉइंटर को मूल्य से पास करते हैं, तो आप इसे एक बार कॉपी करते हैं लेकिन आवश्यकता होने पर ही इसे अस्वीकार करते हैं। यदि इटरेटर-पॉइंटर स्वयं को संदर्भ-सूचक द्वारा पारित किया जाता है, तो इसे फिर से संदर्भित किया जाना चाहिए, बस इटेटरेटर तक पहुंचने के लिए। और वह अनावश्यक है। –

+0

@ शाकम ओह, धन्यवाद! :) –

उत्तर

9

एक बात जो मेरे दिमाग में आती है और संदर्भ में const नेस के खिलाफ है: इसे उपयोग करते समय पुनरावृत्तियों को संशोधित करने की आवश्यकता है।

एक अन्य कार्यान्वयन विवरण यह हो सकता है कि इटरेटर वास्तव में पॉइंटर्स के रूप में लागू किए गए हैं। तो ज्यादातर मामलों में संदर्भ हैं। यदि आप मूल्य से सूचक को पास करते हैं, तो आप इसे एक बार कॉपी करते हैं लेकिन केवल आवश्यकता होने पर इसे अस्वीकार करते हैं। यदि, हालांकि, इटरेटर-पॉइंटर स्वयं को संदर्भ-सूचक द्वारा पारित किया जाता है, तो कि को पहले इसे संदर्भित किया जाना चाहिए, केवल इटेटरेटर तक पहुंचने के लिए, और यह हर बार इटरेटर तक पहुंचने के बाद किया जाना चाहिए। वह अनावश्यक है।

7

कुछ सस्ते-प्रति-प्रति प्रकारों के लिए, मूल्य से उन्हें गुजरना वास्तव में संदर्भ से गुजरने से तेज़ है। ट्यूटोरियल्स, आदि से पारंपरिक ज्ञान, कहता है कि संदर्भ से तेज़ है, लेकिन यह आवश्यक रूप से सस्ती-प्रति-प्रति प्रकारों पर लागू नहीं होता है।

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

इसके अलावा, ध्यान दें कि आप एक कॉन्स्ट संदर्भ पास करने का सुझाव दे रहे हैं। जिसका अर्थ है कि इसे किसी भी तरह से बुलाए गए फ़ंक्शन में संशोधित करने की आवश्यकता होगी (जैसे लूप में वृद्धि)।

5

std इटरेटर की अवधारणा generalisation of a pointer है। std कंटेनर के इटरेटर आमतौर पर एक प्रकार के रूप में लागू होते हैं जो एकल सूचक को बनाते हैं। एक तर्क प्रकार के मामले में जो सूचक के रूप में प्रतिलिपि बनाने के लिए सस्ता है, संदर्भ द्वारा तर्क पारित करना अधिक मूल्य से गुजरने से महंगा है। वस्तु के मूल्य का उपयोग करने से पहले किसी ऑब्जेक्ट का संदर्भ अविकसित होना चाहिए। अधिक जानकारी के लिए this answer देखें।

क्योंकि लगभग सभी std एल्गोरिदम को सर्वश्रेष्ठ प्रदर्शन प्राप्त करने के लिए इटेटरेटर की प्रतिलिपि बनाने की आवश्यकता होती है, यह पहले से ही आवश्यक है कि एक इटरेटर प्रतिलिपि बनाने के लिए सस्ता है। इस कारण से, एक इटरेटर ढूंढना बहुत असामान्य है जो संदर्भ के मुकाबले मूल्य से गुजरने के लिए काफी महंगा है।

std::distance के मामले में - और कई अन्य एल्गोरिदम - संपूर्ण एल्गोरिदम इतना आसान है कि कॉल को संकलक द्वारा रेखांकित किया जाएगा। यदि कॉल रेखांकित है, तो इससे कोई फर्क नहीं पड़ता कि तर्क संदर्भ या मूल्य द्वारा पारित किया गया है या नहीं। [ध्यान दें कि एक इनलाइन फ़ंक्शन कॉल एक इनलाइन फ़ंक्शन घोषणा के समान नहीं है!]

एक पुनरावर्तक के संदर्भ में मूल्य से गुजरने के लिए अधिक महंगा होने के मामले में, और फ़ंक्शन कॉल को रेखांकित नहीं किया जा सकता है, तो आप इसे बना सकते हैं rvalue-संदर्भ द्वारा iterators गुजरने के लिए एक तर्क। ऐसे दुर्लभ मामले में प्रदर्शन लाभ शायद अतिरिक्त जटिलता के लायक नहीं है।

2

अधिकांश एल्गोरिदम अपने तर्कों को संशोधित करते हैं। उदाहरण के लिए, distance रूप इस प्रकार लागू किया जा सकता:

template<class InputIterator> 
typename iterator_traits<InputIterator>::difference_type 
distance (InputIterator first, InputIterator last) { 
    typename iterator_traits<InputIterator>::difference_type result{}; 
    while (first++ != last) 
     ++result; 
    return result; 
} 

जाहिर है इस अगर आप एक const संदर्भ के रूप में first पारित काम नहीं करता।

और यह भी अगर आप क्योंकि ज्यादातर बुला में एक गैर const संदर्भ के रूप में इसे पारित काम नहीं करता संदर्भों फोन करने वाले का वस्तुओं बदला नहीं जा सकता (उदाहरण के लिए यदि आप कार्य करने के लिए container.begin() का परिणाम गुजरती हैं।

बेशक आप अभी भी const संदर्भ द्वारा पारित कर सकता है, समारोह अंदर एक प्रति बनाने और फिर उस संशोधित करते हैं। जो बिंदु पर हम वास्तव में कुछ भी नहीं प्राप्त की है चाहते हैं।

सी ++ मानक सिफारिश है कि iterators हल्के प्रकार होना चाहिए के साथ युग्मित कॉपी करने के लिए सस्ता होना चाहिए, यह अधिक सरल है और सबसे अधिक है मामलों अधिक कुशल उन्हें मूल्य द्वारा पारित करने के लिए:

लेकिन फिर भी अभी भी: सस्ते नकल सभी में कोई नकल से ज्यादा महंगा हो जाएगा।

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


बेशक कोई वास्तविक कार्यान्वयन रैंडम एक्सेस iterators के लिए अनुकूलित किया जाएगा निरंतर बजाय रेखीय क्रम है। उपर्युक्त कार्यान्वयन केवल प्रदर्शनी के लिए है।

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