2012-01-05 15 views
7

मान लीजिए मैं ints का एक वेक्टर,वेक्टर पॉइंटर स्थानों की गारंटी है?

std::vector<int> numbers; 

कि मूल्यों के एक समूह के साथ से भर जाता है, तो मैं कहता हूँ ऐसा करते हैं (जहां एक प्रविष्टि 43 में मौजूद है)

int *oneNumber = &numbers[43]; 

oneNumber होने की गारंटी है है हमेशा सूचकांक 43 पर int पर इंगित करें, भले ही मैं संख्याओं का आकार बदलता हूं जैसे संख्या.resize (46)?

मुझे 100% यकीन नहीं है कि अपेक्षित व्यवहार क्या है, मुझे पता है कि वैक्टरों को संगत होने की गारंटी है लेकिन यह सुनिश्चित नहीं है कि अगर निरंतरता का अर्थ यह भी होगा कि वेक्टर में सभी सूचकांक पूरे जीवन में एक ही स्थान पर बने रहेंगे।

+0

इस कारण से मैं हमेशा मूल्य प्रकार के एक वेक्टर बनाने, क्योंकि मैं अनिवार्य रूप से वेक्टर अंदर वस्तुओं के लिए एक सूचक की जरूरत से सावधान कर रहा हूँ के लिए। तो मैं 'int * ref = और संख्याओं [43]' जैसे संदर्भ को सहेजता हूं .. बाद में 'पुश_बैक' में 'संख्या' और WHAMMO में कुछ करें! बग: 'ref' अमान्य है, क्योंकि' संख्या' पूरी तरह से फिर से आवंटित किया गया है और पूरी तरह से अलग स्मृति स्थान में सहेजा गया है। – bobobobo

+0

@bobobobo बहुत सच है। यद्यपि ऐसी परिस्थितियों के लिए जहां निर्माण समय पर तत्वों की संख्या ज्ञात है (और नहीं, मैं 'std :: array' का उपयोग नहीं कर सकता, क्योंकि मैं 'लूपिंग द्वारा मूल्यों का निर्माण' करता हूं), 'आरक्षित' सभी पॉइंटर्स/इटरेटर की गारंटी देता है वेक्टर में वैध रहेगा, जब तक कि इसकी वर्तमान क्षमता से परे इसका आकार नहीं बदला जाता है (जो एक पुनर्वितरण को मजबूर कर सकता है और इसलिए निहित मूल्यों के पते को स्थानांतरित कर सकता है)। इसने मुझे कुछ बार बचा लिया है, लेकिन हर लगातार समय, मैं 'आरक्षित' करना भूल जाता हूं, और जब तक मुझे याद नहीं आता तब तक मेरे सिर को खरोंच कर लेता है। : डी –

उत्तर

7

से oneNumber हमेशा सूचकांक 43

हाँ, यह मानक द्वारा गारंटीकृत है पर पूर्णांक पर इंगित किए जाने की गारंटी है।

भले ही मैं संख्याओं का आकार बदलता हूं जैसे संख्या.resize (46)?

नहीं। एक बार जब आप वेक्टर में कुछ भी आकार बदलते हैं, जोड़ते हैं या हटाते हैं, तो सभी पते और इटरेटर इसे अमान्य कर दिए जाते हैं। ऐसा इसलिए है क्योंकि वेक्टर को नए मेमोरी स्थानों के साथ फिर से आवंटित करने की आवश्यकता हो सकती है।

+0

यदि आप 'std :: list' का उपयोग करते हैं तो क्या होगा? क्या आप अमान्य पता समस्या को बाधित करेंगे यदि आप केवल आइटम जोड़ने के लिए 'list.push_back() 'कॉल का उपयोग करते हैं? (और आप उस आइटम को नहीं हटाते हैं जो 'OneNumber' अंक है? – bobobobo

+0

@bobobobo यह एक अच्छा सवाल है। मुझे यकीन नहीं है कि मानक इसके बारे में क्या कहता है, लेकिन मुझे कोई कारण नहीं है कि 'std में जोड़ने/निकालने का कोई कारण नहीं है: : सूची' किसी भी पॉइंटर्स को अमान्य कर देगा। (हटाए गए तत्व को छोड़कर) [यदि आप इसमें शामिल होना चाहते हैं तो हम लाउंज में इसकी चर्चा कर रहे हैं।] (http://chat.stackoverflow.com/transcript/message/5559322 # 5559322) – Mysticial

+0

मिला [एक और कामकाज] (http://stackoverflow.com/a/12771369/111307) जिसे मैं वर्तमान में उपयोग कर रहा हूं। – bobobobo

2

नहीं - वेक्टर पुनः आवंटन किया जा सकता है जब यह बढ़ता है। आमतौर पर वेक्टर आकार में दोगुना हो जाता है।

सी ++ 11 मानक

1 Remarks: Causes reallocation if the new size is greater than the old capacity. If no 
reallocation happens, all the iterators and references before the insertion point 
remain valid. If an exception is thrown other than by the copy constructor, move 
constructor, assignment operator, or move assignment operator of T or by any 
InputIterator operation there are no effects. If an exception is thrown by the move 
constructor of a non-CopyInsertable T, the effects are unspecified. 
4

आपका व्यामोह सही है। std::vector का आकार बदलना इसकी स्मृति स्थान को बदल सकता है। इसका मतलब है कि आपका oneNumber अब पुरानी मेमोरी लोकेशन को इंगित कर रहा है जिसे मुक्त कर दिया गया है, और इसलिए इसे एक्सेस करना अपरिभाषित व्यवहार है।

2

आप वेक्टर की क्षमता में वृद्धि करने के लिए एक वेक्टर के आकार() या आरक्षित() फ़ंक्शन का उपयोग करते हैं, यह सरणी-समर्थन के लिए स्मृति को पुनः निर्दिष्ट करना पड़ सकता है। यदि यह पुन: आवंटित करता है, तो नई मेमोरी एक ही पते पर स्थित नहीं होगी, इसलिए OneNumber में संग्रहीत पता अब सही जगह पर इंगित नहीं करेगा।

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

4

प्वाइंटर, संदर्भ, और std::vector तत्वों को iterators जब तक आप केवल std::vectorऔरstd::vector का आकार समय सूचक, संदर्भ में अपनी capacity() परे नहीं उगता से अटैचमेंट के रूप में रखा रहने के लिए, की गारंटी है या इटरेटर प्राप्त किया गया था। एक बार जब यह इस std::vector को capacity() सभी संकेत दिए गए, संदर्भ, और iterators परे आकार दिया जाता है अवैध हो जाते हैं। ध्यान दें कि std::vector के अंत से कहीं और डालने पर चीजें अमान्य भी हैं।

आपके पास करने के लिए अपनी वस्तुओं डाल और आप केवल अंत या शुरुआत में नए तत्व सम्मिलित रहने चाहते हैं, आप std::deque उपयोग कर सकते हैं।std::deque में तत्वों के पॉइंटर्स और संदर्भ केवल std::deque के मध्य में डालने पर या मध्य से हटाते समय या संदर्भित ऑब्जेक्ट को हटाते समय अमान्य हो जाते हैं। ध्यान दें कि std::deque में तत्वों के लिए इटरेटर्स हर बार जब आप std::deque में कोई तत्व डालते हैं या इससे कोई तत्व हटाते हैं तो अमान्य हो जाते हैं।

2

एक बार जब आप वेक्टर की क्षमता बदल देते हैं, तो डेटा को अन्य मेमोरी ब्लॉक में कॉपी किया गया था, और मूल डेटा हटा दिया गया है।

3

सभी अन्य लोगों ने कहा के रूप में की है, जब आप एक वेक्टर पर .resize() फोन अपने संकेत दिए गए अवैध हो जाएगी, क्योंकि (पुराने सरणी) पूरी तरह से deallocated हो सकता है, और पूरी तरह से नया हो फिर से आवंटित कर सकते हैं और अपने डेटा यह में नकल। इस के लिए

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

अपने उदाहरण में

तो,

std::vector<int> numbers; 
int *oneNumber = &numbers[43]; // no. pointers invalidated after .resize or possibly .push_back. 
int oneNumberIndex = 43 ;  // yes. indices remain valid through .resize/.push_back 
संबंधित मुद्दे