-2

I am iterating through a map which has the vector as the V parameter

map<SomeKey, vector<shared_ptr<SomeObject>>

I am iterating over to remove all instances of SomeObject contained in the vectors in this map. I have currently tried a few approaches but each give me some sort of out of range error, or abort().

for (auto iterator = myMap.begin(); iterator != myMap.end(); ) {
    shared_ptr<SomeKey> keyObject = iterator->first;

    //reference the actual vector stored in the map, not a copy
    vector<shared_ptr<SomeObject>> * someObjectList = &myMap[keyObject];

    int index = findIndex(someObject, *someObjectList);

    if (index != -1) {
        auto itr = (*someObjectList).begin() + index;
        &someObjectList->erase(itr);
    }


 //at this point, I do not want the SomeObject to exist in the vectors in the map,
//which is why I am trying to used a vector reference so it doesn't create a copy
    vector<shared_ptr<SomeObject>> list = myMap[keyObject];

    ++iterator;

}

I have managed to get it working without using a referenced vector, and using a local copy, but it doesn't remove from the actual map vector, only the copied one in the current scope.

Can someone provide an example of how I can do this?


This is not a duplicate of the other post as I am not looping over the vector I want to remove elements from. I am looping over a map, that contains a vector.

The vectors are contained inside the map, and I am looking to created a reference vector that points to the one in the map, and remove elements directly from the map's vector.

map<SomeKey, vector<shared_ptr<SomeObject>> myMap;

//loop over map
for (auto it = myMap.begin(); it != myMap.end();) {

         shared_ptr<K> keyObject = it->first;
         vector<shared_ptr<V>> * referenceList = &myMap[keyObject];

         referenceList.erase(myMap.begin() + 1);
         //this would remove it from myMap[keyObject]

}

    auto & clientList = connections[iterator->first];

    for (auto i = clientList.begin(); i != clientList.end(); i++) {
        if ((*i) == client) {
            clientList.erase(i);//abort() thrown here
            break;
        }
    }
jjmcc
  • 795
  • 2
  • 11
  • 27

1 Answers1

0

For this, you want to avoid copy variables created in the loop, you can use something like:

 for(auto m: mymap){
       auto & b =  mymap[m.first]; //direct access to map 

       for(auto i=b.begin(); i<b.end(); i++){ 
                If( (*i) == someobject )
                      b.erase(i); 
         } 
    }

In this manner you have direct access to the vector elements in the map not their copies.

If you have duplicate elements you want to remove, replace

If( (*i) == someobject )

with

while( ((*i) == some object) && (i != b.end()) )
  • Thanks for the response. I've just tried this but I'm still getting an abort() on the `erase` function. I've updated my OP with that new code. – jjmcc Feb 04 '18 at 18:10
  • Actually thanks, this worked. The abort() was being caused by something else. – jjmcc Feb 04 '18 at 18:43
  • @jjmcc The code in this answer is broken, see [this](http://coliru.stacked-crooked.com/a/236d8cc0a3392cec). – HolyBlackCat Feb 05 '18 at 12:44
  • @HolyBlackCat so it is for duplicates. However my vector shouldn't have any duplicates so it seems to work in my case. – jjmcc Feb 05 '18 at 13:22
  • @jjmcc It should be fine if there is no duplicates indeed, but then you better `break;` out of the loop after you erased something. – HolyBlackCat Feb 05 '18 at 13:24
  • @HolyBlackCat my code was to point out the reference usage for mymap. This duplicate in your code can be easily solved if you replace if with while loop, like while((*i)== some object) . I have updated the code. – Kamyar Seifi Feb 05 '18 at 18:10
  • I updated the code – Kamyar Seifi Feb 05 '18 at 18:13
  • I think it should be `i = b.erase(i)`. (Otherwise it's apparently not guaranteed to work according to [this](http://en.cppreference.com/w/cpp/container/vector/erase): *"[erase] Invalidates iterators and references at or after the point of the erase"*). – HolyBlackCat Feb 05 '18 at 18:16
  • @HolyBlackCat here is the thing, the erase function is going to remove the element at that position , then the next element is going to be replaced at that position, and if we do not check it with while loop, then the for loop is going to next position, which in your code is element 3. by adding while loop, it is removing every duplicate that is going to be replaced at that position. therefore i = b.erase(i) is not chaining the position and won't work without while loop. – Kamyar Seifi Feb 05 '18 at 18:27
  • Sorry if that wasn't clear. I agree that it should use `while`, just with `i = `. – HolyBlackCat Feb 05 '18 at 18:31
  • @HolyBlackCat equating i = b.erase(i) is not changing the position of i, therefore it is redundant, see this: http://coliru.stacked-crooked.com/a/93c29291eeff125f , as you can see, the element in the same position is removed, with or without equating i=b.erase(i). since i is already being changed by the for loop. – Kamyar Seifi Feb 05 '18 at 18:35
  • I know that it probably does nothing, but apparently it's not guaranteed to work without it, according to the link I provided. – HolyBlackCat Feb 05 '18 at 18:39
  • return value of erase, points to the next valid element, but at the same time when you delete some element, the next valid element is going to replace the place of the erased element which is the same as current iteration pointer. however it some situations it might be different, like here: [link](http://coliru.stacked-crooked.com/a/f41cd5cd0e5e0801) – Kamyar Seifi Feb 05 '18 at 21:14