2013-06-12 8 views
10

के दौरान वेक्टर में तत्व जोड़ें I मैंने सी ++ 11 मानक द्वारा प्रदान किए गए लूप के लिए नई श्रेणी-आधारित उपयोग किया है और मैं निम्नलिखित प्रश्न के साथ आया हूं: मान लीजिए कि हम vector<> पर पुन: प्रयास करते हैं श्रेणी-आधारित for का उपयोग करके, और हम इस पुनरावृत्ति के दौरान वेक्टर के अंत में कुछ तत्व जोड़ते हैं। इस प्रकार, लूप अंत कब करते हैं?रेंज-आधारित लूप सी ++ 11

उदाहरण के लिए, इस कोड को देखें:

#include <iostream> 
#include <vector> 
using namespace std; 
int main() { 
    vector<unsigned> test({1,2,3}); 
    for(auto &num : test) { 
     cout << num << " "; 
     if(num % 2) 
      test.push_back(num + 10); 
    } 
    cout << "\n"; 
    for(auto &num : test) 
     cout << num << " "; 
    return 0; 
} 

मैं के साथ "-std = C++ 11" झंडा जी ++ 4.8 और एप्पल LLVM संस्करण 4.2 (बजना ++) का परीक्षण किया है, और उत्पादन (दोनों के लिए) है :

1 2 3 
1 2 3 11 13 

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

नोट अगर हम अवैध iterators साथ द्वारा

for(vector<unsigned>::iterator it = test.begin(); it != test.end(); ++it) 

पहले पाश बदल सकते हैं और एक विभाजन गलती के साथ आते हैं कि।

+0

हालांकि जोड़ना मिटाना नहीं है, यह एक डुप्लिकेट है [लूप के लिए एक श्रेणी के अंदर एक कंटेनर से तत्व मिटा रहा है] (http://stackoverflow.com/questions/8624686/erasing-an-element- एक-कंटेनर-जबकि-अंदर-ए-रेंज-आधारित-फॉर-लूप) क्योंकि उत्तर आपको दिखाता है कि मानक कहता है कि मानक क्या है - अंत के लिए निर्धारित होता है और लूप शुरू होने से पहले सहेजा जाता है, और सहेजा गया मूल्य बाद के पुनरावृत्तियों पर प्रयोग किया जाता है। –

+1

@ केटग्रेगरी मैं तर्क दूंगा कि यह एक डुप्लिकेट नहीं है क्योंकि मौजूदा तत्व को हटाने से सभी कंटेनरों के लिए अपरिभाषित व्यवहार होगा, लेकिन तत्व जोड़ना केवल 'std :: vector', 'std :: deque',' std: : unordered_set' और 'std :: unorderd_map'। –

+0

मुझे लगता है कि व्यवहार, व्यवहार से थोड़ा अलग है। कोई बात नहीं धन्यवाद। –

उत्तर

14

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

रेंज पाश

for (range_declaration : range_expression) loop_statement 

के लिए आधारित अनिवार्य रूप से

{ 
    auto && __range = range_expression ; 
    for (auto __begin = std::begin(__range), 
     __end = std::end(__range); 
     __begin != __end; ++__begin) { 
      range_declaration = *__begin; 
      loop_statement 
    } 
} 

के बराबर है, iterators __begin और __end अब वैध नहीं हैं और अपसंदर्भन __begin परिणाम अपरिभाषित व्यवहार में ।

+0

धन्यवाद डेविड। यह दिलचस्प बात है कि कोड के मेरे दो टुकड़े, हालांकि अनिवार्य रूप से समकक्ष, बहुत अलग परिणामों के साथ आते हैं। –

+2

वास्तव में, आप के लिए के बीच disctinction याद कर रहे हैं (ऑटो _begin = r.begin();! _begin = r.end(); ++ शुरू) और (ऑटो- _begin = r.begin() , _end = r.end(); _begin! = _end; ++ _ शुरू) (r.end() की कैशिंग) और * यही कारण है कि आपका प्रोग्राम काम करने की छाप करता है! इटेटरेटर वेक्टर के पुराने संस्करण को इंगित कर रहा है। निहित वस्तुओं में एक विनाशक रखो और Hilarity ensue ... :- डी – Massa

+0

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

0

जब तक वेक्टर की क्षमता काफी बड़ी हो, तब तक आप इस व्यवहार पर भरोसा कर सकते हैं, इसलिए पुनर्वितरण की आवश्यकता नहीं है। यह push_back() पर कॉल करने के बाद पिछले-एंड-एंड इटरेटर के अलावा सभी पुनरावृत्तियों और संदर्भों की वैधता की गारंटी देगा। यह ठीक है क्योंकि end() की गणना लूप की शुरुआत में केवल एक बार की गई थी (std::vector::push_back देखें)।

आपके मामले में, आप इस व्यवहार की गारंटी करने के test वेक्टर की क्षमता में वृद्धि करने के लिए है:

vector<unsigned> test({1,2,3}); 
test.reserve(5); 

संपादित

Is it legal to add elements to a preallocated vector in a range-based for loop over that vector? के लिए प्रतिक्रियाओं के आधार पर, इस अपरिभाषित व्यवहार का एक मामला है। जीसीसी, क्लैंग और सीएल के साथ निर्मित रिलीज संस्करण ठीक चलता है, लेकिन सीएल (विजुअल स्टूडियो) के साथ बनाया गया डीबग संस्करण अपवाद फेंक देगा।