Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to move all the pointers from one vector to another?

Basically what I want to do is remove some of the pointers inside my vector, but I found out that it can be quite slow to do that in the middle of the vector.

So I have a vector that already has data inside:

std::vector<Class*> vec1; // This already contains pointers

I'll iterate through vec1 and will add some of the pointers to another vector (vec2): vec2.push_back(vec1.at(index))

Now I would like to do is something like vec1 = vec2 but I don't know if this is the better (effecient) way to do that.

What would be the best way to do that?

I tried:

  1. While looping through vec1 simply erasing what I need to remove from it:

    it = vec1.erase(it)

  2. While looping through vec1 moving the last item to the actual index and poping_back

    vec1.at(index) = vec1.back(); vec1.pop_back();

  3. Setting some attribute on the object the pointer is pointing while looping through vec1 and than using std::remove_if

    vec1.erase(std::remove_if(vec1.begin(), vec1.end(), shouldBeRemoved), vec1.end());

  4. Now I'm trying to generate a new vector while looping through vec1 and adding the pointers I want to keep, then "swapping" or "moving" the contents of this new vector to vec1.

Apparently when doing it the 4th way, the pointers get invalidated :(

I would love to see what you guys suggest me. A big thank you to everyone that is willing to help!

like image 860
Gabriel Martins Avatar asked Aug 08 '18 09:08

Gabriel Martins


2 Answers

You can just use std::remove_if to conditionally remove items from a vector. This algorithm will shift items that need to be kept over to the front. Follow it up with a std::vector::erase call to actually remove the items not shifted to the front.

This is similar to your option 3, but you don't need to set an attribute first - just use a predicate that determines if the item should be kept or not, and avoid having to pass over the vector twice.

If you don't want to do it in-place, but want to fill a new vector, then std::copy_if does that.

like image 155
Sander De Dycker Avatar answered Oct 03 '22 00:10

Sander De Dycker


Removing things from a vector should be done with the erase remove idiom

It is well covered here: https://en.wikipedia.org/wiki/Erase%E2%80%93remove_idiom

The basic idea is to shift the elements first and then erase the unneeded items which is faster than erasing and shifting each individual element which is done as from the example with:

v.erase( std::remove( v.begin(), v.end(), 5 ), v.end() );

But in general: If you have a lot of add/erase steps in your algorithm, you should use a std::list where removing elements in the middle is much cheaper at all.

like image 25
Klaus Avatar answered Oct 02 '22 22:10

Klaus