2009-05-09 11 views
33

मैं इस तरह एक प्रोटोटाइप के साथ कुछ कार्यों लिखा है:संदर्भ के द्वारा सी ++ इटरेटर पास करने में क्या गड़बड़ है?

template <typename input_iterator> 
int parse_integer(input_iterator &begin, input_iterator end); 

विचार यह है कि फोन करने वाले पात्रों की एक सीमा प्रदान करेंगे और समारोह एक पूर्णांक मान के रूप में पात्रों की व्याख्या और यह वापसी होगी, आखिरी इस्तेमाल किए गए चरित्र से पहले एक बार छोड़ना। उदाहरण के लिए:

std::string sample_text("123 foo bar"); 
std::string::const_iterator p(sample_text.begin()); 
std::string::const_iterator end(sample_text.end()); 
int i = parse_integer(p, end); 

यह foo से पहले अंतरिक्ष में 123 और p "की ओर इशारा करते" करने के लिए i सेट छोड़ना होगा।

मुझे तब से बताया गया है (स्पष्टीकरण के बिना) कि संदर्भ के अनुसार एक इटरेटर पास करने के लिए यह खराब रूप है। क्या यह खराब रूप है? यदि हां, तो क्यों?

उत्तर

29

वास्तव में गलत कुछ भी नहीं है, लेकिन यह निश्चित टेम्पलेट के उपयोग को सीमित होगा। आप किसी अन्य चीज़ द्वारा वापस इटरेटर वापस नहीं कर पाएंगे या v.begin() जैसे उत्पन्न नहीं होंगे, क्योंकि वे अस्थायी होंगे।आपको हमेशा स्थानीय प्रतिलिपि बनाना होगा, जो किसी प्रकार का बॉयलरप्लेट है जो वास्तव में अच्छा नहीं है। आप वापस जाने के लिए वापसी मान होगा

template<typename input_iterator, typename output_iterator> 
input_iterator parse_integer(input_iterator begin, input_iterator end, 
          output_iterator out); 

:

int parse_integer(input_iterator begin, input_iterator end, 
        input_iterator &newbegin); 

template<typename input_iterator> 
int parse_integer(input_iterator begin, input_iterator end) { 
    return parse_integer(begin, end, begin); 
} 

एक अन्य विकल्प एक निर्गम इटरेटर जहां संख्या में लिखा जाएगा है:

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

int i; 
b = parse_integer(b, end, &i); 

std::vector<int> numbers; 
b = parse_integer(b, end, std::back_inserter(numbers)); 
+2

"आप किसी अन्य चीज़ द्वारा लौटाए गए इटरेटर को या v.begin() की तरह जेनरेट नहीं कर पाएंगे, क्योंकि वे अस्थायी होंगे।" यही कारण है कि सी ++ 0x रैवल्यू संदर्भ हैं। :) – Zifre

+0

मुझे आउटपुट इटरेटर विचार पसंद है यह बहुत stl-esque – iain

+1

एक और विकल्प (देर से पाठकों के लिए): एक :: std :: pair को लौट रहा है, जैसा कि :: std :: map :: insert करता है । – Aconcagua

3

सामान्य में:

यदि आप एक गैर const संदर्भ गुजरती हैं, फोन करने वाले अगर iterator संशोधित किया जा रहा है पता नहीं है।

आप const संदर्भ पास कर सकते हैं, लेकिन आमतौर पर इटरेटर इतने छोटे होते हैं कि यह मूल्य से गुजरने पर कोई लाभ नहीं देता है।

आपके मामले में:

मैं वहाँ आप क्या करते हैं के साथ कुछ भी गलत है, सिवाय इसके कि यह भी iterator उपयोग के बारे में मानक-esque नहीं है नहीं लगता।

-1

आपके फ़ंक्शन घोषणा के दूसरे पैरामीटर में संदर्भ गुम है, है ना?

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

बस एक सुझाव: अपने पैरामीटर सावधानीपूर्वक टाइप करें।

+0

नहीं, दूसरा पैरामीटर उद्देश्य पर मूल्य-मूल्य था, क्योंकि संदर्भ द्वारा इसे पास करने की आवश्यकता नहीं है। हां, संदर्भ से गुजरने से फ़ंक्शन पैरामीटर को बदलने की अनुमति देता है। वह इरादा था। मैं तुम्हारी बात समझ में नहीं आता। इटरेटर बदलना "पूरे अनुक्रम को खराब नहीं कर सकता है।" इटरेटर बदलना सीमा में डेटा को बदलने से अलग है। ये सभी के बाद 'const_iterators' थे। –

1

मुझे लगता है कि मानक लाइब्रेरी एल्गोरिदम विशेष रूप से मूल्य से इटरेटर को पास करते हैं (कोई अब इस के लिए एक स्पष्ट अपवाद पोस्ट करेगा) - यह विचार की उत्पत्ति हो सकती है। बेशक, कुछ भी नहीं कहता है कि आपका खुद का कोड मानक पुस्तकालय की तरह दिखना है!

2

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

इस उदाहरण में हालांकि आपको दो मान वापस करने की आवश्यकता है: पार्स किए गए int मान, और, नया/संशोधित इटरेटर मूल्य; और यह देखते हुए कि एक फ़ंक्शन में दो रिटर्न कोड नहीं हो सकते हैं, एक गैर-कॉन्स्ट संदर्भ के रूप में रिटर्न कोड में से एक कोडिंग आईएमओ सामान्य है।

एक वैकल्पिक इस तरह यह कुछ कोड करने के लिए होगा:

//Comment: the return code is a pair of values, i.e. the parsed int and etc ... 
pair<int, input_iterator> parse(input_iterator start, input_iterator end) 
{ 
} 
+0

मैं भी एक जोड़ी वापस करने की सोच रहा था, लेकिन इसके लिए आवेदन कोड पर कुछ बॉयलरप्लेट की आवश्यकता है ... जब तक आप boost :: टाई के लिए नहीं जाते। – Reunanen

2

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

हालांकि, इस मामले में यह तो आम है के लिए iterators मूल्य तर्क मुझे लगता है कि यह एक विशेष रूप से बुरा विचार गैर स्थिरांक संदर्भ द्वारा iterators गुजरती हैं और पारित कर दिया iterator संशोधित करने के लिए है के रूप में इलाज किया जाना है। यह आमतौर पर बेवकूफ तरीके के खिलाफ चला जाता है इटरेटर आमतौर पर उपयोग किया जाता है।

चूंकि आप क्या चाहते हैं कि इस समस्या नहीं है ऐसा करने के लिए एक शानदार तरीका है, मुझे लगता है कि आप इसका इस्तेमाल करना चाहिए:

template <typename input_iterator> 
int parse_integer(input_iterator* begin, input_iterator end); 

अब एक फोन करने वाले क्या करना है जाएगा:

int i = parse_integer(&p, end); 

और यह स्पष्ट होगा कि इटरेटर बदला जा सकता है।

वैसे, मुझे नए पुनरावर्तक को वापस करने और पार्स किए गए मानों को आउटपुट इटरेटर द्वारा निर्दिष्ट स्थान में डालने के litb's suggestion भी पसंद है।

1

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

यह ध्यान देने योग्य है कि आपका दृष्टिकोण (एक स्ट्रीमर टोकनिंग करते समय आप कहां हैं, इसका ट्रैक रखने के संदर्भ में एक इटरेटर को पास करना) वास्तव में दृष्टिकोण है जो boost::tokenizer द्वारा लिया जाता है। विशेष रूप से, TokenizerFunction Concept की परिभाषा देखें। कुल मिलाकर, मुझे बूस्ट :: टोकनेज़र को बहुत अच्छी तरह डिज़ाइन किया गया और अच्छी तरह से सोचा गया।

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