Consider this hypothetical implementation of vector
:
template<class T> // ignore the allocator
struct vector
{
typedef T* iterator;
typedef const T* const_iterator;
template<class It>
void insert(iterator where, It begin, It end)
{
...
}
...
}
Problem
There is a subtle problem we face here:
There is the possibility that begin
and end
refer to items in the same vector, after where
.
For example, if the user says:
vector<int> items;
for (int i = 0; i < 1000; i++)
items.push_back(i);
items.insert(items.begin(), items.end() - 2, items.end() - 1);
If It
is not a pointer type, then we're fine.
But we don't know, so we must check that [begin, end)
does not refer to a range already inside the vector.
But how do we do this? According to C++, if they don't refer to the same array, then pointer comparisons would be undefined!
So the compiler could falsely tell us that the items don't alias, when in fact they do, giving us unnecessary O(n) slowdown.
Potential solution & caveat
One solution is to copy the entire vector every time, to include the new items, and then throw away the old copy.
But that's very slow in scenarios such as in the example above, where we'd be copying 1000 items just to insert 1 item, even though we might clearly already have enough capacity.
std::less
etc, which are guaranteed to give a total order, even when the raw pointer comparisons do not. – Davenavector
s defined in the standard have undefined behaviour if you try to do this, because the iterators become invalidated by theinsert
. (Not to discourage an implementation which extends/modifiesstd::vector
to support this). – Davenaless(p1, p2)
doesn't engage in UB, whereasp1 < p2
does?? I didn't know that! – Dip[comparisons]/8: For templates greater, less, greater_equal, and less_equal, the specializations for any pointer type yield a total order, even if the built-in operators <, >, <=, >= do not.
– Davenaif
. Why would you suffer O(n) slowdown all the time? – Vangif
implementation doesn't work correctly. – Dipif
implementation. – Vangstd::rotate
, right? – Dipstd::rotate
is basically a loop of swaps right? I've never used it. But actuallystd::rotate_copy
might be all the swapping logic I described already written for you. – Vang