यदि आप मानचित्र तत्व पर मिटना शुरू करते हैं तो क्या होता है?


133

निम्नलिखित कोड में मैं एक मानचित्र के माध्यम से लूप करता हूं और परीक्षण करता हूं कि क्या किसी तत्व को मिटाना है। क्या तत्व को मिटाना और इसे सुरक्षित रखना सुरक्षित है या क्या मुझे किसी अन्य कंटेनर में चाबियां एकत्र करने और इरेज़ () को कॉल करने के लिए दूसरा लूप करने की आवश्यकता है?

map<string, SerialdMsg::SerialFunction_t>::iterator pm_it;
for (pm_it = port_map.begin(); pm_it != port_map.end(); pm_it++)
{
    if (pm_it->second == delete_this_id) {
        port_map.erase(pm_it->first);
    }
}

अद्यतन: बेशक, मैंने तब यह प्रश्न पढ़ा था जो मुझे नहीं लगता था कि संबंधित होगा लेकिन मेरे प्रश्न का उत्तर देता है।


कृपया ध्यान दें कि std::remove_ifstd:map
सॉकेटपेयर

जवाबों:


183

सी ++ 11

यह C ++ 11 में तय किया गया है (या मिटा दिया गया है / सभी कंटेनर प्रकारों में सुसंगत बनाया गया है)।
मिटा विधि अब अगला पुनरावृत्ति देता है।

auto pm_it = port_map.begin();
while(pm_it != port_map.end())
{
    if (pm_it->second == delete_this_id)
    {
        pm_it = port_map.erase(pm_it);
    }
    else
    {
        ++pm_it;
    }
}

सी ++ 03

किसी मानचित्र में तत्वों को मिटाना किसी पुनरावृत्तियों को अमान्य नहीं करता है।
(हटाए गए तत्व पर पुनरावृत्तियों के अलावा)

वास्तव में सम्मिलित करना या हटाना किसी भी पुनरावृत्तियों को अमान्य नहीं करता है:

इस उत्तर को भी देखें:
मार्क रैनसम तकनीक

लेकिन आपको अपना कोड अपडेट करने की आवश्यकता है:
आपके कोड में आप erase call के बाद pm_it को बढ़ाते हैं। इस बिंदु पर यह बहुत देर हो चुकी है और पहले से ही अमान्य है।

map<string, SerialdMsg::SerialFunction_t>::iterator pm_it = port_map.begin();
while(pm_it != port_map.end())
{
    if (pm_it->second == delete_this_id)
    {
        port_map.erase(pm_it++);  // Use iterator.
                                  // Note the post increment.
                                  // Increments the iterator but returns the
                                  // original value for use by erase 
    }
    else
    {
        ++pm_it;           // Can use pre-increment in this case
                           // To make sure you have the efficient version
    }
}

क्या pm_it++फ़ंक्शन में प्रवेश करने से पहले निष्पादित होने की गारंटी पोस्टफ़िक्स एक्सप्रेशन में वेतन वृद्धि का मूल्यांकन है?
डेविड रॉड्रिग्ज -

4
@ डेविड रॉड्रिग्ज़ - ड्रिबीज़: हाँ। मानक गारंटी देता है कि फ़ंक्शन कहने से पहले सभी तर्क अभिव्यक्तियों का पूरी तरह से मूल्यांकन किया जाएगा। यह उस पद वृद्धि का परिणाम है जिसे मिटा समारोह () में पारित किया जाता है। तो हाँ er_ () के आने से पहले pm_it का पोस्ट इन्क्रीमेंट किया जाएगा।
मार्टिन यॉर्क

नोट: लाइन के लिए लगभग लाइन स्कॉट मेयर के "प्रभावी एसटीएल" आइटम 9 में साहचर्य कंटेनर उदाहरण से मेल खाती है।
ओगरे Psalm33

for (auto pm_t = port_map.begin (); pm_it! = port_map.end ();) {...}
एंड्री सिरोकोमस्की

4
@iboisver: वेक्टर पर। मिटा () का उपयोग इरेज़ बिंदु के बाद सरणी के सभी पुनरावृत्तियों को अमान्य करता है (केवल अंत नहीं), यह Sequenceकंटेनरों की एक संपत्ति है । Associativeकंटेनरों की विशेष संपत्ति यह है कि पुनरावृत्तियों को मिटाने या डालने से अमान्य नहीं किया जाता है (जब तक कि वे उस तत्व को इंगित नहीं करते हैं जो मिटा दिया गया था)। वेक्टर और इरेज़ यूज इट्रैटर उपयुक्त प्रश्न में विस्तार से कवर किया गया है stackoverflow.com/a/3938847/14065
मार्टिन यॉर्क

12

यहां बताया गया है कि मैं ऐसा कैसे करता हूं ...

typedef map<string, string>   StringsMap;
typedef StringsMap::iterator  StrinsMapIterator;

StringsMap m_TheMap; // Your map, fill it up with data    

bool IsTheOneToDelete(string str)
{
     return true; // Add your deletion criteria logic here
}

void SelectiveDelete()
{
     StringsMapIter itBegin = m_TheMap.begin();
     StringsMapIter itEnd   = m_TheMap.end();
     StringsMapIter itTemp;

     while (itBegin != itEnd)
     {
          if (IsTheOneToDelete(itBegin->second)) // Criteria checking here
          {
               itTemp = itBegin;          // Keep a reference to the iter
               ++itBegin;                 // Advance in the map
               m_TheMap.erase(itTemp);    // Erase it !!!
          }
          else
               ++itBegin;                 // Just move on ...
     }
}

यदि आप वेक्टर के अंत के साथ-साथ (itEnd) को हटाते हैं, तो अंतिम जांच (जबकि स्थिति) एक अमान्य पुनरावृत्ति (itEnd) के विरुद्ध होगी। अच्छा नही।
आगस्टिनो

1

यह मैं इसे कैसे करूंगा, लगभग:

bool is_remove( pair<string, SerialdMsg::SerialFunction_t> val )
{
    return val.second == delete_this_id;
}

map<string, SerialdMsg::SerialFunction_t>::iterator new_end = 
    remove_if (port_map.begin( ), port_map.end( ), is_remove );

port_map.erase (new_end, port_map.end( ) );

कुछ अजीब बात है

val.second == delete_this_id

लेकिन मैंने अभी इसे आपके उदाहरण कोड से कॉपी किया है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.