2012-10-03 28 views
83

'के लिए' मैं सेल्सियस के लिए नया हूँ ++ भाषा का उपयोग करते हुए। मैं वैक्टरों का उपयोग शुरू कर रहा हूं, और ध्यान दिया है कि इंडेक्स के माध्यम से वेक्टर के बावजूद मैं जिस कोड को फिर से देखता हूं, for लूप का पहला पैरामीटर हमेशा वेक्टर पर आधारित होता है। जावा में मैं एक ArrayList के साथ कुछ इस तरह कर सकते हैं:एक सी ++ वेक्टर के माध्यम से दोहराएं एक पाश

for(int i=0; i < vector.size(); i++){ 
    vector[i].doSomething(); 
} 

एक कारण मैं इस सी ++ में नहीं दिख रहा है है? क्या यह बुरा अभ्यास है?

+0

लूप के लिए एक फ़ंक्शन नहीं है, इसलिए इसमें पैरामीटर नहीं हैं (या तर्क, जो आप पास करते हैं)। क्या आपका मतलब है 'std :: vector :: size_type i = 0; ', हालांकि, या शायद' std :: vector :: iterator it = vector.begin(); '? – chris

+0

बिल्कुल, मेरे द्वारा देखे जाने वाले सभी उदाहरण इस तरह लिखे गए हैं। – Flynn

+4

जावा में, मैं प्रत्येक लूप के लिए या iterators का उपयोग करना पसंद करेंगे। सी ++ के रूप में काफी कुछ हालांकि थोड़ा अलग वाक्यविन्यास। –

उत्तर

59

है:

आप अभी भी अनुक्रमित का उपयोग करना चाहते हैं, तो तरीका है? क्या यह बुरा अभ्यास है?

नहीं, ये एक बुरी प्रथा नहीं है, लेकिन यह आपके कोड कुछ लचीलापन बना देता है।

std::vector<int>::iterator it = vector.begin(); 

इसका कारण यह है कि यह कोड और अधिक लचीला बनाता है:

आमतौर पर, पूर्व सी ++ 11 कंटेनर तत्वों से अधिक पुनरावृत्ति के लिए कोड iterators, की तरह कुछ का उपयोग करता है।

सभी मानक लाइब्रेरी कंटेनर समर्थन करते हैं और इटरेटर प्रदान करते हैं और देखते हैं कि यदि विकास के बाद के बिंदु पर आपको एक और कंटेनर स्विच करने की आवश्यकता है तो इस कोड को बदलने की आवश्यकता नहीं है।

नोट: लेखन कोड जो हर संभावित मानक लाइब्रेरी कंटेनर के साथ काम करता है, उतना आसान नहीं है जितना प्रतीत होता है।

+16

क्या कोई मुझे बता सकता है कि इस विशेष मामले/कोड स्निपेट में आप इंडेक्सिंग को इंडेक्सिंग पर क्यों सलाह देते हैं? यह "लचीलापन" आप किस बारे में बात कर रहे हैं? निजी तौर पर, मुझे इटरेटर पसंद नहीं हैं, वे कोड को फटकारते हैं - एक ही प्रभाव के लिए टाइप करने के लिए बस अधिक वर्ण। विशेष रूप से यदि आप 'ऑटो' का उपयोग नहीं कर सकते हैं। –

+5

@ व्हायोलेट जिराफ: इटरेटर्स का उपयोग करते समय रिक्त रेंज जैसे कुछ मामलों के साथ गलत होना मुश्किल है और कोड अधिक वर्बोज़ है। इसके मामले या धारणा और पसंद का पालन करें, इसलिए इसे अंतहीन रूप से बहस की जा सकती है। –

50

एक वेक्टर के माध्यम से पुनरावृत्ति की स्पष्ट तरीका iterators के माध्यम से है: (ऊपर के बराबर)

for (auto & element : vector) { 
    element.doSomething(); 
} 

पहले C++ 0x को

for (auto it = begin (vector); it != end (vector); ++it) { 
    it->doSomething(); 
} 

या आपके द्वारा ऑटो बदलने के लिए ग्लोबल फ़ंक्शंस के बजाय इटरेटर प्रकार और सदस्य फ़ंक्शन का उपयोग शुरू होता है और समाप्त होता है।

यह शायद तुम क्या देखा है। आपके द्वारा उल्लेख किए गए दृष्टिकोण की तुलना में, लाभ यह है कि आप vector के प्रकार पर भारी निर्भर नहीं हैं। यदि आप vector को एक अलग "संग्रह-प्रकार" वर्ग में बदलते हैं, तो आपका कोड शायद अभी भी काम करेगा। हालांकि, आप जावा में कुछ भी समान कर सकते हैं। अवधारणा में बहुत अंतर नहीं है; सी ++, हालांकि, इसे लागू करने के लिए टेम्पलेट का उपयोग करता है (जावा में जेनेरिक की तुलना में); इसलिए दृष्टिकोण सभी प्रकार जिसके लिए begin और end कार्यों परिभाषित कर रहे हैं, यहां तक ​​कि इस तरह के स्थिर सरणियों के रूप में गैर-वर्ग प्रकार के लिए के लिए काम करेंगे। यहाँ देखें: How does the range-based for work for plain arrays?

+4

ऑटो, फ्री स्टार्ट/एंड भी सी ++ 11 है। और भी, आपको ++ इसके बजाय, कई मामलों में ++ का उपयोग करना चाहिए। – ForEveR

+0

हाँ, आप सही हैं। हालांकि, 'स्टार्ट' और 'एंड' लागू करना एक लाइनर है। – JohnB

+0

@ जॉन बी यह एक से अधिक लाइनर है, क्योंकि यह निश्चित आकार के सरणी के लिए भी काम करता है। दूसरी तरफ 'ऑटो' काफी मुश्किल होगी। – juanchopanza

27

कि करने के लिए सही तरीका है:

for(std::vector<T>::iterator it = v.begin(); it != v.end(); ++it) { 
    it->doSomething(); 
} 

कहाँ टी वेक्टर के अंदर वर्ग के प्रकार है। उदाहरण के लिए यदि कक्षा कैक्टिविटी थी, तो टी

इस प्रकार की विधि प्रत्येक एसटीएल (न केवल वैक्टर, जो थोड़ा बेहतर है) पर काम करेगी। ऐसा कोई कारण है कि मैं इस सी ++ में नहीं दिख रहा है

for(std::vector<T>::size_type i = 0; i != v.size(); i++) { 
    v[i].doSomething(); 
} 
+0

'std :: वेक्टर :: size_type' हमेशा' size_t' नहीं है? यही वह प्रकार है जिसका मैं हमेशा इसके लिए उपयोग करता हूं। –

+1

@ व्हायोलेट जिराफ मुझे यकीन है कि आप सही हैं (वास्तव में चेक नहीं किया है), लेकिन यह std :: vector :: size_type का उपयोग करने के लिए एक बेहतर अभ्यास है। – DiGMi

+0

"वर्जित" इंडेक्स तरीका दिखाने के लिए धन्यवाद। – Rosenthal

4

एसटीएल के साथ, प्रोग्रामर कंटेनर के माध्यम से ट्रैवर्सिंग के लिए iterators का उपयोग करते हैं, क्योंकि इटरेटर एक सार अवधारणा है, जो सभी मानक कंटेनरों में लागू होता है। उदाहरण के लिए, std::list में operator [] कोई भी नहीं है।

67

कारण आपको ऐसा अभ्यास क्यों नहीं दिख रहा है, यह काफी व्यक्तिपरक है और इसका कोई निश्चित जवाब नहीं हो सकता है, क्योंकि मैंने iterator शैली कोड के बजाय आपके निर्दिष्ट तरीके का उपयोग करने वाले कई कोड देखे हैं।

बाद पाशन के vector.size() रास्ता पर विचार नहीं लोगों के कारण हो सकते हैं:

  1. पाश हालत में size() बुला हर बार के बारे में पागल होने के नाते। हालांकि या तो यह एक गैर मुद्दा है या यह for पाश पर ही तुच्छता निश्चित
  2. पसंद करते हैं std::for_each() हो सकता है
  3. बाद में एक दूसरे के लिए std::vector से कंटेनर को बदलने (जैसे map, list) भी के परिवर्तन की मांग करेंगे तंत्र, पाशन वजह से नहीं हर कंटेनर

सी ++ 11 पाशन के समर्थन size() शैली कंटेनर के माध्यम से स्थानांतरित करने के लिए एक अच्छा सुविधा प्रदान करता है। इसे "लूप के लिए रेंज आधारित" कहा जाता है (या जावा में "लूप के लिए बढ़ाया गया") कहा जाता है।

थोड़ा कोड आप पूर्ण के माध्यम से पार कर सकते हैं के साथ

std::vector (अनिवार्य!):

vector<int> vi; 
... 
for(int i : vi) 
    cout << "i = " << i << endl; 
+4

लूप_ के लिए आधारित _range के एक छोटे से नुकसान को नोट करने के लिए: आप इसे '#pragma omp समानांतर' के साथ उपयोग नहीं कर सकते हैं। – liborm

+1

मुझे कॉम्पैक्ट संस्करण पसंद है क्योंकि पढ़ने के लिए कम कोड है। एक बार जब आप मानसिक समायोजन कर लेते हैं तो यह समझना बहुत आसान होता है और बग अधिक खड़े हो जाते हैं। यह गैर-मानक पुनरावृत्ति होने पर भी अधिक स्पष्ट हो जाता है क्योंकि कोड का एक बड़ा हिस्सा है। –

5

वहाँ मजबूत कारणों iterators उपयोग करने के लिए, जिनमें से कुछ यहाँ उल्लेख कर रहे हैं की एक जोड़ी है:

स्विचिंग कंटेनर बाद में आपके कोड को अमान्य नहीं करता है।

यानी, यदि आप std :: vector से std :: list, या std :: set पर जाते हैं, तो आप अपने निहित मान प्राप्त करने के लिए संख्यात्मक सूचकांक का उपयोग नहीं कर सकते हैं। एक पुनरावर्तक का उपयोग करना अभी भी मान्य है।

रनटाइम अवैध यात्रा के पकड़ने

आप अपने पाश, अगली बार के बीच में अपने कंटेनर को संशोधित करते हैं तो आप अपने इटरेटर का उपयोग यह गलत इटरेटर अपवाद फेंक देते हैं।

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