std::vector::erase avoiding lots of copying

May 2, 2011 at 2:54pm
I have situation where i have lots of objects in one container and i need to erase some element/s from arbitary position,
but that can envolve lots of copying being made, so i thought i should try to swap object from that position with last one
and erase that one. First question, is there some common function for this one?
Currently i have wrote this:
1
2
3
4
5
6
7
template<typename T>
void erase(std::vector<T>& v, ulong inx)
{
	std::vector<T>::iterator itr = v.begin() + inx;
	std::swap(*itr, v.back());
	v.erase(v.end() - 1);
}

Note that afer this i don't need right order of elements since i will sort afterwards.

Second question, how to "grab" const_iterator for last element so that i dont need to write:
v.erase(v.end() - 1);

Feel free to point any flows you can see here.

Thanks for your time.
Last edited on May 2, 2011 at 2:54pm
May 2, 2011 at 2:57pm
Second question, how to "grab" const_iterator for last element so that i dont need to write:


You could just v.pop_back(); instead of using erase.
May 2, 2011 at 2:59pm
You can improve it (a little bit) like so:

1
2
3
4
5
6
template<typename T>
void erase(std::vector<T>& v, ulong inx)
{
	std::swap(v[inx], v.back());
	v.pop_back();
}
May 2, 2011 at 3:05pm
Thank you for hints.

I just realized that i can add one more swap after pop_back and regain order:
1
2
3
4
5
6
7
template<typename T>
void erase_element(std::vector<T>& v, ulong inx)
{
	std::swap(v[inx], v.back());
	v.pop_back();
        std::swap(v[inx], v.back());
}
Last edited on May 2, 2011 at 3:12pm
May 2, 2011 at 4:02pm
That doesn't regain the original order. There's no way to do that without moving every element after the removed one.
May 2, 2011 at 4:05pm
I meant sorted order, not by index order.
Last edited on May 2, 2011 at 4:05pm
May 2, 2011 at 4:16pm
There's a difference?

Let's say you have the following data:

1 2 5 8 10 23

anr you remove the 5:

1 2 23 8 10 5 <- 1st swap
1 2 23 8 10 <- pop_back
1 2 10 8 23 <- 2nd swap

Order isn't restored.
May 2, 2011 at 4:34pm
OMG. You're right. Damn it.
May 2, 2011 at 4:40pm
Hmm. Maybe you could setup a vector of pairs which contain the values and the original subscripts of all the data, and after you're done erasing everything that needs to be erased you could just sort by the original subscripts.

-Albatross
May 2, 2011 at 4:43pm
If you need the data to stay sorted, just use the built-in erase() function. No need to reinvent the wheel here.

Although your custom function above is good if you don't need it to be sorted.
May 2, 2011 at 4:47pm
What he's trying to avoid is a vector's need to shift all the data after the erased element to maintain an array-like structure. Maybe he has a good reason for that.

Although, why not use an std::deque? It has some higher constant factors, true, but its erase() does seem to me to be a bit more efficient than an std::vector's, albeit not as efficient as an std::list's (though lists have some efficiency problems in other areas...).

-Albatross
Last edited on May 2, 2011 at 4:53pm
May 2, 2011 at 4:54pm
just use the built-in erase()

What built in? std::vector::erase() ? But what if i invoke that on 0 inx of vector of 5000 elements that would invoke almost 5000 copyies just to shift elements?

I would like (if possible) after erase if elements can remain sorted in few cheap steps, so that i don't need to call sort immideatly after.
If you have some ideas please share.
Thanks greatly on your time.
Last edited on May 2, 2011 at 4:55pm
May 2, 2011 at 5:15pm
But what if i invoke that on 0 inx of vector of 5000 elements that would invoke almost 5000 copyies just to shift elements?


Yeah, but if you want it to stay sorted, that's what it takes.

The alternative would be to use something like deque as Albatross suggested. It offers [potentially] faster insertion/removal with a tradeoff of [potentially] slower data access.

Or if you don't need random access you could use a list instead.

I would like (if possible) after erase if elements can remain sorted in few cheap steps


If such a thing were possible, vector::erase would do it. The people that wrote those libs knew what they were doing.
May 2, 2011 at 5:21pm
You're right (again). Thanks both of you for tips.
Topic archived. No new replies allowed.