Reputation: 61
Which is the smartest way to add at the beggining of a vector the last two elements of the vector itself and add at the end of the vetor the first two element of the vector? I mean, if my starting vector is
v = 1 2 3 4 5 6 7 8 9
I need that it becames
v = 8 9 1 2 3 4 5 6 7 8 9 1 2
Upvotes: 0
Views: 869
Reputation: 592
By using the vector::insert function for ranges. It is easier to first insert the first two elements at the end.
v.insert(v.end(), v.begin(), v.begin()+2);
v.insert(v.begin(), v.end()-2, v.end());
Edit: Is undefined behaviour.
Appending std::vector to itself, undefined behavior?
Upvotes: 0
Reputation: 279245
First, if the container is going to be large then consider using deque
instead of vector
. It's more efficient for adding at the start.
For vector
you can't insert elements out of the vector
to the start because the first thing that happens is everything in the vector gets moved (and all iterators and references to those elements are invalidated). So you either need to copy the elements out of the vector or you need to put insert elements at the start and then copy-assign to them. Assuming the type is int
, I'll go with the former:
if (v.size() >= 2) {
int tmp[] = {*(v.end() - 2), *(v.end() - 1)};
v.insert(v.begin(), tmp, tmp + 2);
tmp[0] = v[2]; tmp[1] = v[3];
v.insert(v.end(), tmp, tmp + 2);
}
Alternatively, this uses more memory but might be easier to read. As a bonus it gives the strong exception guarantee even with types whose copy constructor can throw. My code above can be made to offer the strong guarantee by adding a call to reserve
, but only because int
is a trivial type:
if (v.size() >= 2) {
std::vector<int> new_v;
new_v.reserve(v.size() + 4);
new_v.insert(new_v.end(), v.end() - 2, v.end());
new_v.insert(new_v.end(), v.begin(), v.end());
new_v.insert(new_v.end(), v.begin(), v.begin() + 2);
v.swap(new_v);
}
For deque
you don't need to store any elements outside the container provided you use a reference instead of an iterator to access them. Again this only offers the basic exception guarantee.
if (v.size() >= 2) {
v.push_front(v.back());
v.push_front(*&(v.end() - 1));
v.push_back(*&(v.begin() + 2));
v.push_back(*&(v.begin() + 3));
}
Upvotes: 5
Reputation: 310950
My five cents
std::vector<int> v = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
v.insert( v.end(), { v[0], v[1], v[v.size() - 2], v[v.size() - 1] } );
std::rotate( v.begin(), std::prev( v.end(), 2 ), v.end() );
for ( int x : v ) std::cout << x << ' ';
std::cout << std::endl;
Upvotes: 2