2009-06-04 5 views
21

पर विचार करें:map.erase (map.end())?

#include <map> 

int main() 
{ 
    std::map< int, int > m; 
    m[ 0 ] = 0; 
    m[ 1 ] = 1; 

    m.erase(0); // ok 
    m.erase(2); // no-op 
    m.erase(m.find(2)); // boom! 
} 

(। ठीक है, तो शीर्षक वार्ता समाप्त() इटरेटर मिटा abouting, लेकिन() एक गैर-मौजूद कुंजी के लिए अंत वापस आ जाएगी लगता है)

क्यों एक गैर मिटा रहा है -मुख कुंजी ठीक है, फिर भी अंत मिटा रहा है() उड़ाता है। मैं मानक में इसका कोई स्पष्ट उल्लेख नहीं देख सका?

मैंने इसे VS2005 (डीबग कॉन्फ़िगरेशन में अपवाद फेंक दिया) और जीसीसी 4.0.1 (100% सीपीयू) पर कोशिश की है। क्या यह कार्यान्वयन निर्भर है?

धन्यवाद।

उत्तर

30

erase(key) के लिए, मानक कहता है कि मूल्य कुंजी वाले सभी तत्व हटा दिए जाते हैं। निश्चित रूप से ऐसा कोई मूल्य नहीं हो सकता है।

For erase(it) (जहां it एक std::map::iterator है), मानक का कहना है कि तत्व बताया करने से यह निकाल दिया जाता है - दुर्भाग्य से, अगर यह end() है यह एक वैध तत्व को इंगित नहीं करता है और आप अपरिभाषित व्यवहार देश में बंद कर रहे हैं , जैसा कि आप होगा यदि आपने किसी अन्य मानचित्र ऑपरेशन के लिए end() का उपयोग किया था। अधिक जानकारी के लिए खंड 23.1.2 देखें।

+3

स्पष्टीकरण के लिए: मिटाएं() के विभिन्न ओवरलोड हैं, और इटरेटर संस्करण को एक वैध तत्व की आवश्यकता है। – rlbond

+12

मिटाएं (यह) मिटाने के बराबर है (यह, ++ इटरेटर (इसे)), जो मुझे यह देखने में मदद करता है कि मिटाएं (यह) इसके साथ अमान्य है = map.end()। .end() के बाद आपको एक और इटरेटर की आवश्यकता होगी। –

+0

कोई भी मानक के लिए एक लिंक प्रदान कर सकते हैं? –

18

end() मानचित्र में एक मध्यस्थ नहीं है। यह प्रभावी रूप से मानचित्र के अंत में 'एक अतीत' है।

'इटेटरेटर' संस्करण मानचित्र में कुछ इटेटरेटर चाहता है।
मिटाने का 'कुंजी' संस्करण लुकअप करता है और कुंजी के खिलाफ खुद को सुरक्षित करता है, इटरेटर संस्करण मानता है कि आप सामान तोड़ने की कोशिश नहीं कर रहे हैं।

+0

"मानता है कि आप सामान तोड़ने की कोशिश नहीं कर रहे हैं" ... मैं समझता हूं, मुझे उम्मीद है कि यह मिटाएगा (यह) एक साधारण जांच करेगा! = अंत() –

+0

एक अनुचित विचार नहीं है, यह सिर्फ इतना है कि एसटीएल कंटेनर के ऐसे चेक के ओवरहेड नहीं चाहते हैं। मिटाने जैसे मामलों में, प्रवेशकर्ता को मिटाना चाहते हैं, इससे पहले कि इटरेटर का उपयोग किसी और चीज के लिए किया जा सकता है, इसलिए वे अंत के लिए चेक छोड़ देते हैं - क्योंकि आप शायद पहले से ही कर चुके हैं। मुख्य मामले में, यह अधिक संभावना है कि कॉलर को पता नहीं है कि कुंजी मानचित्र में है या नहीं, इसलिए वे चेक करते हैं। –

+0

पिछली टिप्पणी में जोड़ें, बस मानचित्र को बेहतर समझने के लिए: यह एक बाइनरी सर्च ट्री है (मानक को इसे ऑर्डर करने की आवश्यकता होती है; आमतौर पर लाल-काले पेड़ के रूप में लागू किया जाता है), और एक कुंजी मिटाने के लिए, पहले इसे ढूंढने की आवश्यकता होती है वैसे भी, चाहे वह अस्तित्व में है या नहीं - तो कोई पेड़ को लटक रहा है (मिटाएं (कुंजी) एक ओ (लॉग एन) ऑपरेशन बना रहा है) वैसे भी, और एक अस्तित्वहीन कुंजी को स्वीकार करने से कोई अतिरिक्त काम नहीं होता है (जैसा कि चेक करेगा मिटाने में (इसे)), इसलिए इनपुट के रूप में इसे स्वीकार करना तार्किक है। – Aconcagua

1

यहां एक त्वरित उदाहरण है कि मैं इसे हटाने के दौरान एसटीएल मानचित्र का उपयोग कैसे करता हूं। एक डालने पर भी वही काम करता हूं। व्यक्तिगत रूप से मैं नक्शा को विशेष रूप से परिभाषित करने के लिए टाइपपीफ का उपयोग करना पसंद करता हूं, लेकिन पसंद तुम्हारा है।


typedef std::map... MapType; 

MapType the_map; 

MapType::iterator it = the_map.find ("key"); 
if (it != the_map.end()) { 
    // Do something productive. 
    the_map.erase (it); 
} 

MapType::iterator it = the_map.find ("new_key"); 

// Does not exist. 
if (it == the_map.end()) { 
    the_map.insert (std::make_pair ("new_key", 10)); 
} 

आशा है कि इससे मदद मिलती है!

3
एक पिछली पोस्ट में दिए गए उदाहरण के बजाय

...

MapType::iterator it = the_map.find ("new_key"); 

// Does not exist. 
if (it == the_map.end()) { 
    the_map.insert (std::make_pair ("new_key", 10)); 
} 

जो दो पेड़ traversals, उपयोग करता है ...

pair<MapType::iterator, bool> rc = the_map.insert(make_pair("new_key", 0)); 
if (rc.second) 
    rc.first.second = 10; 

इस तरह आप एक पेड़ ट्रेवर्सल करते हैं और आपके पास इटेटरेटर अन्य सामान के लिए रोल करने के लिए तैयार है।