2010-03-15 20 views
9

से कैसे बचें क्योंकि सदिश तत्वों को संगत रूप से संग्रहीत किया जाता है, मुझे लगता है कि इसमें कुछ push_back के बाद एक ही पता नहीं हो सकता है, क्योंकि प्रारंभिक आवंटित स्थान पर्याप्त नहीं हो सकता है।क्या std :: vector अपना पता बदलता है?

मैं एक कोड है, जहां मैं एक सदिश में एक तत्व के लिए एक संदर्भ की जरूरत है, की तरह पर काम कर रहा हूँ:

int main(){ 
    vector<int> v; 
    v.push_back(1); 
    int *ptr = &v[0]; 
    for(int i=2; i<100; i++) 
     v.push_back(i); 
    cout << *ptr << endl; //? 
    return 0; 
} 

लेकिन यह जरूरी सच नहीं है कि ptrv[0] के लिए एक संदर्भ है, है ना शामिल? इसकी गारंटी देने का एक अच्छा तरीका कैसे होगा?

मेरा पहला विचार पॉइंटर्स और गतिशील आवंटन के वेक्टर का उपयोग करना होगा। मैं सोच रहा हूं कि ऐसा करने का कोई आसान तरीका है?

पीएस .: वास्तव में मैं int के बजाय कक्षा के वेक्टर का उपयोग कर रहा हूं, लेकिन मुझे लगता है कि मुद्दे समान हैं।

+7

क्यों आपको इसकी आवश्यकता होने पर '& v [0]' क्यों नहीं मिलता है? – kennytm

+2

आप पॉइंटर के बजाय तत्व की अनुक्रमणिका रख सकते हैं और उसके बाद() 0 ऑपरेटर [] –

+0

@ केनीटीएम का उपयोग करके इसे एक्सेस कर सकते हैं हालांकि: यह मेरे वास्तविक कोड में ऊपर वर्णित नहीं है, मैं यह नहीं बता सकता कि कौन सी अनुक्रमणिका तक पहुंच है अब जब मुझे इसकी ज़रूरत है। – kunigami

उत्तर

12

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

आप वेक्टर में तत्वों का पता लेने से बचें, यदि संभवतः पुन: आवंटन की अप्रत्याशित प्रकृति की वजह से संभवतः। आप के लिए है, तो उपयोग iterators कच्चे पतों की बजाय, के बाद से जाँच की एसटीएल कार्यान्वयन आपको बता देंगे, जब वे बजाय बेतरतीब ढंग से दुर्घटनाग्रस्त का अमान्य हो गई हैं,।

सबसे अच्छा समाधान अपने कंटेनर बदलने के लिए है:

  • आप एसटीडी इस्तेमाल कर सकते हैं :: सूची - यह मौजूदा iterators जब तत्वों को जोड़ने को अमान्य नहीं है, और केवल एक मिट तत्व को इटरेटर अवैध है जब
  • मिटाकर
  • आप C++ 0x, std :: वेक्टर < std :: unique_ptr < टी उपयोग कर रहे हैं > >,
  • वैकल्पिक रूप से एक दिलचस्प समाधान है संकेत दिए गए हैं और नए/हटाना बहुत बुरा नहीं है का उपयोग कर - बस डॉन ' पॉइंटर्स बी को मिटाना भूल जाते हैं उन्हें मिटा दें। इस तरह से सही होना मुश्किल नहीं है, लेकिन आपको हटाना भूलकर स्मृति रिसाव का कारण बनने के लिए बहुत सावधान रहना होगा। (मार्क Ransom यह भी बताता है: यह अपवाद सुरक्षित एक अपवाद का कारण बनता है वेक्टर नष्ट हो अगर, पूरे वेक्टर सामग्री लीक कर रहा है नहीं है।)
  • ध्यान दें कि बढ़ावा के ptr_vector एसटीएल एल्गोरिदम से कुछ के साथ सुरक्षित रूप से नहीं किया जा सकता है, जो हो सकता है आपके लिए एक समस्या हो
+1

नए/हटाए गए पॉइंटर्स जब कोई वैक्टर नष्ट नहीं होता है तो एक समस्या मौजूद होती है - उदाहरण के लिए एक अपवाद के कारण। –

+0

अच्छा बिंदु, संपादन। – AshleysBrain

+0

आईएमओ: std :: सूची में बहुत कम उपयोग हैं। मैं इसके बजाय std :: डेक की सिफारिश करेंगे। –

10

आप अपने reserve सदस्य फ़ंक्शन को कॉल करके वेक्टर द्वारा इस्तेमाल किया अंतर्निहित सरणी के क्षमता में वृद्धि कर सकते हैं: जब तक आप वेक्टर में 100 से अधिक तत्वों डाल नहीं के रूप में

v.reserve(100); 

, ptr को इंगित करेगा पहला तत्व

+1

चूंकि 'आरक्षित' रिजर्व कम से कम जितना आप पूछते हैं, आप वेक्टर में 'क्षमता' तत्वों को रख सकते हैं। – Bill

+0

अब समस्या यह है कि मुझे नहीं पता कि कितनी जगह का उपयोग किया जाएगा। क्या यह पर्याप्त उच्च मूल्य का उपयोग करने का एक अच्छा विचार है? कुछ मामलों में, केवल 10^6 सुरक्षित होगा, लेकिन अन्य मामलों में 100 पर्याप्त होगा। – kunigami

+1

यदि आप नहीं जानते कि आप कितने तत्व स्टोर करने जा रहे हैं, तो आरक्षित करना एक बीएडी विचार है! जब तक वेक्टर उस क्षमता से अधिक हो जाता है, तब तक आप अपने लटकते पॉइंटर बग को बाद में स्थगित कर रहे हैं! – AshleysBrain

6

इसकी गारंटी देने का एक अच्छा तरीका कैसे होगा?

std::vector<T> सतत होने की गारंटी है, लेकिन कार्यान्वयन वेक्टर सामग्री में फेरबदल कार्यों पर पुनः आवंटित करने के लिए स्वतंत्र या नि: शुल्क संग्रहण है (तत्वों के लिए वेक्टर iterators, संकेत या संदर्भ अपरिभाषित रूप में अच्छी तरह हो जाते हैं)।

हालांकि, आप reserve पर कॉल करके अपना वांछित परिणाम प्राप्त कर सकते हैं। आईआईआरसी, मानक गारंटी देता है कि वेक्टर के आकार तक आरक्षित होने की तुलना में कोई पुनर्वितरण नहीं किया जाता है।

आम तौर पर, मैं इसके साथ सावधान रहूंगा (आप जल्दी से फंस सकते हैं ...)। std::vector<>::reserve और इटरेटर दृढ़ता पर भरोसा न करें जब तक आपको वास्तव में नहीं करना पड़े।

2

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

+2

अमान्यता पॉइंटर्स के उपयोग पर निर्भर करेगी। यदि 'int * ptr = &v[0];' सूची में किसी विशिष्ट आइटम का प्रतिनिधित्व करने के लिए है, तो हां, इसे अमान्य किया जा सकता है, लेकिन यदि यह सूची में पहले आइटम का प्रतिनिधित्व करने के लिए है, जो भी हो, तो यह नहीं होगा अवैध ठहरा दिया। – Bill

+0

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

1

अपनी आवश्यकताओं और उपयोग के मामले के आधार पर, आप Boost's Pointer Container Library पर एक नज़र डालना चाहेंगे।

आपके मामले में आप boost::ptr_vector<yourClass> का उपयोग कर सकते हैं।

5

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

template <class T> 
class vec_ptr { 
    std::vector<T> &v; 
    size_t index; 
public: 
    vec_ptr(std::vector<T> &v, size_t index) : v(v), index(index) {} 

    T &operator*() { return v[index]; } 
}; 

फिर अपने int *ptr=&v[0]; की तरह कुछ के साथ प्रतिस्थापित किया जाएगा: vec_ptr<int> ptr(v,0);

अंक की एक जोड़ी: सब से पहले, अगर आप समय के बीच अपने वेक्टर में आइटम को पुनर्व्यवस्थित आप "सूचक" और बार जब आप इसे भिन्नता, यह अब मूल तत्व का उल्लेख होगा, लेकिन करने के लिए जो कुछ भी तत्व निर्दिष्ट स्थान पर होने वाला पैदा करते हैं। दूसरा, यह कोई सीमा जाँच करता है, तो (उदाहरण के लिए) एक सदिश कि केवल 50 आइटम शामिल हैं अपरिभाषित व्यवहार दे देंगे में 100 वें आइटम का उपयोग करने के लिए प्रयास।

2

आप अपने मूल्यों समीपवर्ती संग्रहीत की जरूरत नहीं है, तो आप std :: Deque बजाय std :: वेक्टर उपयोग कर सकते हैं। यह पुन: आवंटित नहीं करता है, लेकिन स्मृति के कई हिस्सों में तत्व रखता है।

1

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

  1. वेक्टर में कच्चे डेटा को बचाने और पाने के सापेक्ष सूचकांक
  2. के बाद वेक्टर बढ़ रही बंद कर दिया, पते

सूचक को सूचकांक में परिवर्तित मैं निम्नलिखित काम करता पाया

  1. पॉइंटर्स [i] = सूचकांक [i] + (size_t) & वेक्टर [0];
  2. पॉइंटर्स [i] = & वेक्टर [(size_t) सूचकांक [i]];

हालांकि, मैं पता लगा नहीं है कि कैसे vector.front (उपयोग करने के लिए) और मुझे यकीन है कि क्या मैं संकेत का उपयोग करना चाहिए नहीं कर रहा हूँ [i] = सूचकांक [i] * sizeof (वेक्टर) + (size_t) & वेक्टर [0]। मुझे लगता है कि संदर्भ तरीका (2) बहुत सुरक्षित होना चाहिए।

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