2009-06-24 7 views
25

गले से आप एक कंटेनर में तत्व को मिटाना/हटा नहीं सकते हैं, जबकि इटरेटर अमान्य हो जाता है। किसी निश्चित स्थिति को पूरा करने वाले तत्वों को हटाने के लिए (सुरक्षित) तरीके क्या हैं? कृपया केवल एसएलएल, कोई बढ़ावा या tr1।मैप (या किसी अन्य एसटीएल कंटेनर) से सामग्री को मिटाएं/हटाएं

संपादित वहाँ एक और अधिक सुरुचिपूर्ण तरीका अगर मैं तत्वों है कि एक कुछ मानदंडों को पूरा, शायद functor और for_each का उपयोग कर या एल्गोरिथ्म मिटा के साथ के एक नंबर को मिटाना चाहते हैं है? एसटीडी के साथ

उत्तर

9
bool IsOdd(int i) 
{ 
    return (i&1)!=0; 
} 

int a[] = {1,2,3,4,5}; 
vector<int> v(a, a + 5); 
v.erase(remove_if(v.begin(), v.end(), bind1st(equal_to<int>(), 4)), v.end()); 
// v contains {1,2,3,5} 
v.erase(remove_if(v.begin(), v.end(), IsOdd), v.end()); 
// v contains {2} 
+0

bind1st क्या है? – 0xC0DEFACE

+0

bind1st ऑब्जेक्ट की तरह एक फ़ंक्शन बनाता है जो अनिवार्य रूप से आपको स्थिर पहले पैरामीटर के साथ एक फ़ंक्शन कॉल देता है - इसलिए उदाहरण में इसका बराबर_(4, एक्स) का प्रभाव होगा जहां एक्स अनुक्रम से आता है जिसे हम फिर से चालू कर रहे हैं। प्रभाव यह है कि अनुक्रम में प्रत्येक मान की तुलना 4 से कम होती है। – markh44

9

उदाहरण :: वेक्टर

#include <vector> 

using namespace std; 

int main() 
{ 

    typedef vector <int> int_vector; 

    int_vector v(10); 

    // Fill as: 0,1,2,0,1,2 etc 
    for (size_t i = 0; i < v.size(); ++i){ 
     v[i] = i % 3; 
    } 

    // Remove every element where value == 1  
    for (int_vector::iterator it = v.begin(); it != v.end(); /* BLANK */){ 
     if (*it == 1){ 
     it = v.erase(it); 
     } else { 
     ++it; 
     } 
    } 

} 
+1

इसके बारे में नहीं पता था, लेकिन क्या यह एक नया, मान्य एक मिटाने से वापस आ गया है? बहुत अजीब लगता है कि यह एक अवैध इटरेटर वापस करेगा? –

+2

अन्यथा एक पुनरावर्तक लौटने का मुद्दा क्या होगा? –

+7

@j_random_hacker: आप सही हैं कि यह किसी भी iterators को अमान्य करता है .. लेकिन std :: vector :: मिटा देता है * मिटा * (* अंत) के बाद तत्व के लिए * नया *, * वैध * इटरेटर देता है। यह कोड पूरी तरह से मान्य है। –

31

आप जब तक आप अपने इटरेटर को अमान्य नहीं है के रूप में आप यह मिट करने के बाद कर सकते हैं:

MyContainer::iterator it = myContainer.begin(); 
while(it != myContainer.end()) 
{ 
    if (*it == matchingValue) 
    { 
     myContainer.erase(it++); 
    } 
    else 
    { 
     ++it; 
    } 
} 
+15

+1। "MyContainer.erase (यह ++)," सूक्ष्म है - यह * कॉलिंग मिटाएं() से पहले वृद्धि * सही ढंग से निष्पादित करता है, जब यह अभी भी ऐसा करने के लिए मान्य होता है, जबकि उस कार्य के लिए * अनियंत्रित * इटरेटर को पास करते हुए (प्रतिलिपि)। –

+16

महत्वपूर्ण: यह कोड मानचित्र, सेट और सूची के लिए काम करता है, लेकिन यह वेक्टर के लिए काम नहीं करेगा - एक वेक्टर से मिटाने से इटेटर को अमान्य करता है और उसके बाद के सभी तत्व (23.2.4.3/3)। अब के लिए मेरा +1 गिरा दिया है, जब आप इसका उल्लेख करते हैं तो फिर से +1 होगा। –

+0

क्या आप वाकई मिटाने से पहले वृद्धि चाहते हैं? AFAIK वृद्धि के वाक्य से पहले वृद्धि की गारंटी है, लेकिन सही क्रम कार्यान्वयन विशिष्ट है। उदाहरण के लिए डीबग मोड में एक gnu इस 'v.erase (it), ++ 'की तरह कुछ करता है, लेकिन रिलीज मोड में' tmp = it, ++ it, v.erase (tmp)' है। – Ismael

2
template <class Container, class Predicate> 
void eraseIf(Container& container, Predicate predicate ) { 
    container.erase(remove_if(container.begin(), container.end(), predicate), container.end()); 
} 

template<class K, class V, class Predicate> 
void eraseIf(map<K,V>& container, Predicate predicate ) { 
    for(typename map<K,V>::iterator iter=container.begin() ; iter!=container.end() ; ++iter) { 
     if(predicate(iter)) 
      container.erase(iter); 
    } 
} 
+1

हालांकि मानचित्र के साथ काम नहीं करता है। –

+1

अब यह करता है ... – TimW

+0

नक्शा संस्करण मिटा दिए जाने के बाद एक इटरेटर को बढ़ाने की कोशिश करता है (और इसलिए अमान्य है)। – interjay

2

मैं while के साथ संस्करण पसंद करें:

typedef std::list<some_class_t> list_t; 
void f(void) { 
    // Remove items from list 
    list_t::iterator it = sample_list.begin(); 
    while (it != sample_list.end()) { 
    if (it->condition == true) { 
     it = sample_list.erase(it); 
    } else ++it;  
    } 
} 

while के साथ it को दो बार बढ़ाने के लिए कोई खतरा नहीं है क्योंकि यह for लूप में हो सकता है।

1

markh44 सबसे अधिक एसटीएल-ईश प्रतिक्रिया है। नोट, हालांकि, सामान्यतः, कंटेनर को संशोधित करके इटरेटर्स को अमान्य कर दिया जाता है, लेकिन सेट और मानचित्र अपवाद हैं। वहां, आप आइटम्स को हटा सकते हैं और फिर भी इटरेटर का उपयोग कर सकते हैं, सिवाय इसके कि अगर आप उस आइटम को हटाते हैं जो आपके इटेटरेटर संदर्भित कर रहा है।

3

विक्टर के समाधान को हटाने से पहले तत्व के साथ कुछ करने में सक्षम होने का उछाल है। (। मैं remove_if या remove_copy_if के साथ ऐसा करने में सक्षम नहीं था) लेकिन मैं std::find_if उपयोग करने के लिए तो मैं iterator अपने आप को बढ़ाने के लिए कभी नहीं पसंद करते हैं:

typedef vector<int> int_vector; 
int_vector v; 

int_vector::iterator itr = v.begin(); 
for(;;) 
{ 
    itr = std::find_if(itr, v.end(), Predicate(4)); 
    if (itr == v.end()) 
    { 
     break; 
    } 

    // do stuff with *itr here 

    itr = v.erase(itr); // grab a new, valid iterator 
} 

विधेय कहाँ bind1st(equal_to<int>(), 4) या कुछ इस तरह हो सकता है:

struct Predicate : public unary_function<int, bool> 
{ 
    int mExpected; 
    Predicate(int desired) : mExpected(desired) {} 
    bool operator() (int input) 
    { 
     return (input == mExpected); 
    } 
}; 
1

इस तथ्य का उपयोग करें कि पोस्ट-कमीशन ऑपरेटर की प्रतिलिपि से पहले की कमी देता है। चूंकि घटित इटरेटर अभी भी मौजूदा तत्व को मिटाने के बाद मान्य है, इसलिए लूप उद्देश्य के रूप में काम करना जारी रखता है।

#include <list> 
std::list<int> myList; 
for(int i = 0; i < 10; ++i) 
{ 
    myList.push_back(i); 
} 

int cnt = 0; 
for(std::list<int>::iterator iter = myList.begin(); iter != myList.end(); ++iter) 
{ 
    if(cnt == 5) 
    { 
     myList.erase(iter--); 
    } 
    ++cnt; 
} 

संपादित करें: यदि आप सूची में पहले तत्व को मिटाने के लिए प्रयास करने के काम नहीं करता ....

2

1. std::vector<>:

std::vector <int> vec; 
vec.erase(std::remove(vec.begin(),vec.end(), elem_to_remove), vec.end()); 

2. std::map<> हमेशा उपयोग std::map::erase()

std::map<int,std::string> myMap; 
myMap.emplace(std::make_pair(1, "Hello")); 
myMap.emplace(std::make_pair(2, "Hi")); 
myMap.emplace(std::make_pair(3, "How")); 
myMap.erase(1);//Erase with key 
myMap.erase(myMap.begin(), ++myMap.begin());//Erase with range 
for(auto &ele: myMap) 
{ 
    if(ele.first ==1) 
    { 
     myMap.erase(ele.first);//erase by key 
     break; //You can't use ele again properly 
       //wthin this iteration, so break. 
    } 
} 
  1. फो आर std::liststd::list::erase()
संबंधित मुद्दे