2010-07-20 47 views
29

के तत्वों के लिए पॉइंटर्स मेरे पास std::vector कुछ वर्ग ClassA के तत्वों के साथ std::vector है। इसके अतिरिक्त मैं std::map<key,ClassA*> का उपयोग करके एक इंडेक्स बनाना चाहता हूं जो वेक्टर में निहित तत्वों के पॉइंटर्स को कुछ महत्वपूर्ण मानों को मानचित्रित करता है।std :: vector और std :: list

कोई गारंटी नहीं है कि इन संकेत (एक ही वस्तु के लिए और बिंदु) वैध रहेगा है जब तत्व हैं वेक्टर ( नहीं डाला ) के अंत में गयी। यानी, निम्नलिखित कोड सही होगा:

std::vector<ClassA> storage; 
std::map<int, ClassA*> map; 

for (int i=0; i<10000; ++i) { 
    storage.push_back(ClassA()); 
    map.insert(std::make_pair(storage.back().getKey(), &(storage.back())); 
} 
// map contains only valid pointers to the 'correct' elements of storage 

कैसे है स्थिति, अगर मैं std::list बजाय std::vector का उपयोग करें?

+1

वेक्टर का उद्देश्य क्या है? क्या आपको उस क्रम को याद रखने की ज़रूरत है जिसमें उन्हें बनाया गया है? आप मानचित्र और इसके बजाय vecor का उपयोग कर सकते हैं। मानचित्र के तत्वों के लिए Iterators/पॉइंटर्स/संदर्भ मान्य रहते हैं। अपने पसंदीदा मानक पुस्तकालय संदर्भ की गारंटी देखें। – sellibitze

उत्तर

24

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

सूचियाँ - हाँ, डालने और हटाने तत्वों अन्य तत्वों

+1

उत्तरों को उलट दिया जाना चाहिए, वैक्टर -> नहीं और सूचियां -> हां सवाल यह है कि "क्या कोई गारंटी है कि ये पॉइंटर्स वैध रहते हैं?" – Naveen

+0

@Naveen - जैसा कि इंगित किया गया है, धन्यवाद। – DumbCoder

+0

एक 'डेक' भी एक अच्छा विकल्प हो सकता है, अगर यादृच्छिक पहुंच और तत्व जोड़ने पर कोई आवंटन नहीं चाहता है। – foraidt

9

जहां तक ​​मैं समझता हूं, ऐसी कोई गारंटी नहीं है। वेक्टर में तत्व जोड़ना तत्वों को पुन: आवंटन का कारण बनता है, इस प्रकार मानचित्र में आपके सभी पॉइंटर्स को अमान्य कर देता है।

+0

यही मैंने सोचा था। क्या आप 'std :: list' के बारे में जानते हैं? आखिरकार, अगर इसे लिंक की गई सूची के रूप में लागू किया गया है, तो पुनर्वितरण की कोई आवश्यकता नहीं होगी ... – MartinStettner

+1

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

1

की ओर इशारा, संदर्भ, और iterators को अमान्य नहीं है बस उन्हें बनाने के दोनों दुकान जब आप उन्हें ज़रूरत नहीं है एक स्पष्ट वस्तुओं को हटाने के संकेत करती हैं।

std::vector<ClassA*> storage; 
std::map<int, ClassA*> map; 

for (int i=0; i<10000; ++i) { 
    ClassA* a = new ClassA() 
  storage.push_back(a) 
  map.insert(std::make_pair(a->getKey(), a)) 
} 
// map contains only valid pointers to the 'correct' elements of storage 
+3

मैं एसटीएल कंटेनर में नग्न पॉइंटर्स को संग्रहीत करने के खिलाफ दृढ़ता से सलाह दूंगा। यह लीक के लिए एक नुस्खा है। – sbi

+0

एचएम, यह वही है जो मैं टालने का प्रयास करता हूं :)। मैं इस मामले में केवल अपनी मानचित्र का उपयोग कर सकता हूं (मेरी समस्या के लिए), मैं सिर्फ स्मृति कंटेनर की देखभाल करने के लिए कुछ कंटेनर रखना चाहता हूं। – MartinStettner

+0

संपादन के लिए धन्यवाद (आईपैड पर और अर्ध-कॉलन प्रारूपित या प्रारूपित नहीं कर सकते हैं)। – Tom

3

मुझे यकीन है कि क्या यह गारंटी है नहीं कर रहा हूँ, लेकिन व्यवहार में storage.reserve(needed_size) सुनिश्चित करें कि कोई reallocations होते हैं बनाना चाहिए।

लेकिन आप इंडेक्स क्यों स्टोर नहीं करते?
इंडेक्स को इटेटरेटर (storage.begin()+idx) में जोड़कर इंडेक्स में कनवर्ट करना आसान है और किसी भी इटरेटर को पहले इसे संदर्भित करके पॉइंटर में बदलना आसान है, और उसके बाद अपना पता (&*(storage.begin()+idx)) लेना आसान है।

+0

समस्या यह है, कि मैं नहीं जानता कि 'पहले से needed_size' (मैं स्वीकार करते हैं कि कोड को सरल बनाया एक सा है ...) भंडारण सूचकांक एक विकल्प होगा, लेकिन मैं यह भी कार्यक्रम के विभिन्न अन्य भागों में संकेत दिए गए पास करनी होगी जो वेक्टर तक पहुंच नहीं होनी चाहिए (फिर कोड उस पहलू को नहीं दिखाता है) – MartinStettner

+0

@ मार्टिनस्टेटनर: आप आसानी से वेक्टर के लिए इंडेक्स को पॉइंटर्स में बदल सकते हैं। मैंने इसका उत्तर विस्तारित करने के लिए विस्तारित किया है। – sbi

+1

पूरी चीज एक कक्षा में encapsulated है जो "बाहरी" के लिए पॉइंटर्स पास करने की जरूरत है, कार्यक्रम के अन्य हिस्सों भी इन पॉइंटर्स को स्टोर कर सकते हैं, इसलिए उन्हें स्थिर होना चाहिए। यदि मैंने आपके दृष्टिकोण का उपयोग किया है तो मुझे शुरुआत() इटेटरेटर भी प्रदान करना होगा जो encapsulation का उल्लंघन होगा (वेक्टर स्टोरेज एक आंतरिक कार्यान्वयन विस्तार होना चाहिए ...)। – MartinStettner

6

std::deque का उपयोग करें! तत्वों के पॉइंटर्स स्थिर होते हैं जब केवल push_back() का उपयोग किया जाता है।

नोट: तत्वों के लिए इटरेटर को अमान्य किया जा सकता है! तत्वों के लिए पॉइंटर्स नहीं होगा।

संपादित करें: C++ deque's iterator invalidated after push_front()

+1

क्या आप इस बारे में निश्चित हैं? क्या इस दावे को कवर करने वाले सी ++ मानक में कोई हिस्सा है? यह इस तरह से समय की सबसे लागू किया जा सकता है, लेकिन मैं गारंटी के कुछ प्रकार की आवश्यकता है ... – MartinStettner

+0

क्यों पुनरावर्तक, जो मूल रूप से एक सूचक * विशेष रूप से है कि कंटेनर * के लिए बनाया गया है, अवैध जाना चाहिए, लेकिन नहीं एक कच्चे सूचक है, जो स्मृति स्मृति (और एक प्रकार) के अलावा कुछ भी नहीं दर्शाता है? – foraidt

+2

@mxp: एक पुनरावर्तक को अगले तत्व को खोजने में सक्षम होना चाहिए। इस क्षमता को इटरेटर में अतिरिक्त जानकारी की आवश्यकता है, और यह अतिरिक्त जानकारी अमान्य हो सकती है। – Sjoerd

1

एक और जवाब देने के लिए टिप्पणियों में से एक से ऐसा प्रतीत होता है जैसे कि सब जो आप चाहते को केंद्रीकृत (आसानी) स्मृति प्रबंधन है: क्या यह उत्तर विवरण क्यों बताते हैं। यदि यह वास्तव में मामला है, तो आपको boost pointer container लाइब्रेरी जैसे प्रीपेक्टेड समाधानों का उपयोग करने पर विचार करना चाहिए और जितना संभव हो सके अपना कोड रखें।

विशेष रूप से, वैक्टर के लिए ptr_map

+0

इसे इंगित करने के लिए बहुत बहुत धन्यवाद। दुर्भाग्य से इस परियोजना के एक बड़े ग्राहक जो नहीं है (अभी तक) अपने कोड में बढ़ावा पुस्तकालय शामिल करना चाहते हैं के लिए है (हालांकि यह समस्याओं का एक बहुत कम हैं :) ...) – MartinStettner

0
  1. पर एक नज़र डालें नहीं।
  2. सूचियों के लिए हाँ। कैसे? इटेटरेटर सूची में किसी विशेष नोड को पॉइंटर के रूप में काम करता है। ताकि आप किसी भी संरचना को मान निर्दिष्ट कर सकें:

    मेरी सूची सूचीबद्ध करें;

    जोड़ी < सूची :: iterator, int> temp;

    temp = make_pair (mylist.begin(), x);

+0

यह सचमुच [DumbCoder के] के रूप में ही जवाब है (https://stackoverflow.com/a/3287828/501011), केवल 7 साल बहुत देर हो चुकी है और हर पहलू –

+0

में बदतर मैं इसी तरह की समस्या थी और एक साधारण उदाहरण के लिए देख रहा था। चूंकि उपर्युक्त उत्तरों में से कोई भी नहीं था, इसलिए मैंने खुद को एक उदाहरण लिखना सोचा। –

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