views:

556

answers:

5

How come that random deletion from a std::vector is faster than a std::list? What I'm doing to speed it up is swapping the random element with the last and then deleting the last. I would have thought that the list would be faster since random deletion is what it was built for.

for(int i = 500; i < 600; i++){
    swap(vector1[i], vector1[vector1.size()-1]);
    vector1.pop_back();
}

for(int i = 0; i < 100; i++){
        list1.pop_front();
}

Results (in seconds):
Vec swap delete: 0.00000909461232367903
List normal delete: 0.00011785102105932310

+13  A: 

What you're doing is not random deletion though. You're deleting from the end, which is what vectors are built for (among other things).

And when swapping, you're doing a single random indexing operation, which is also what vectors are good at.

jalf
Indeed. I don't see any randomness there.
Mehrdad Afshari
Then what is the purpose of a std::list when with a single swap a vector is faster and gives random access?
Psykocyber
That depends if you want to keep the vector in order or not
1800 INFORMATION
A std::list is particularly useful when you need to be able to insertions and/or deletions at any position. You're not doing this.
Matthew Flaschen
Right you are, my bad.
Psykocyber
Consider the case when your object in your vector / list has an extremely expensive copy constructor.
sharth
And on top of that, he's proceeding through the vector in order (from both directions), so he's making optimal use of cache, unlike the list scenario.
Greg Rogers
A: 

That's not random. Try vector1.erase(vector.begin() + rand() % vector.size()); instead.

Marcus Lindblom
I know that is true random, but the purpose was to see if a list or vector would be the best for a program with a lot of truly random deletion. I know that way is slower than a list.
Psykocyber
A: 

The list erase will cause to delete the erased list element, this will invoke a call to the delete operator. The vector erase just causes a swap and then a integer decrement - this is a lot faster.

1800 INFORMATION
when writing erase you mean pop_back ? AFAIK pop_back() isn't swapping the underlying array (which would mean it has created it before which is time consuming). It only decrease the vector's size then call the destructor ?
yves Baumes
ACtually , as far as i remember, a vector never trim itself. You need to implement the "swap trick" as called by Scott Meyer , with another vector instance this time with a **capacity** reduced at its best.
yves Baumes
yeah sorry I meant the pop_back and pop_front calls. In the case of the list it is implemented in terms of erase
1800 INFORMATION
A: 

Actually if you want further speed-ups you should index elements in the vector via iterators. They are known to have better performance for some architectures.

Sergio
Care to elaborate there?
rama-jka toti
If your architecture doesn't have a pointer+index memory access mode, and/or is short of registers for what you're doing, then it's plausible to come up with situations where accessing by index takes an extra instruction or so over accessing by pointer/iterator. Of course you may lose this if you call end() in the loop condition and the compiler doesn't (or can't) optimise it outside the loop.
Steve Jessop
+2  A: 

The difference between std::list and std::vector is not merely down to performance. They also have different iterator invalidation semantics. If you erase an item from a std::list, all iterators pointing to other items in the list remain valid. Not so with std::vector, where erasing an item invalidates all iterators pointing after that item. (In some implementations, they may still serve as valid iterators, but according to the standard they are now unusable, and a checking implementation ought to assert if you try to use them.)

So your choice of container is also to do with what semantics you require.

Daniel Earwicker