Moving elements from std::vector to another one - c++

How can I move some elements from first vector to second, and the elements will remove from the first?
if I am using std::move, the elements not removed from first vector.
this is the code I wrote:
move(xSpaces1.begin() + 7, xSpaces1.end(), back_inserter(xSpaces2));

Resurrecting an old thread, but I am surprised that nobody mentioned std::make_move_iterator combined with insert. It has the important performance benefit of preallocating space in the target vector:
v2.insert(v2.end(), std::make_move_iterator(v1.begin() + 7),
std::make_move_iterator(v1.end()));
As others have pointed out, first vector v1 is now in indeterminate state, so use erase to clear the mess:
v1.erase(v1.begin() + 7, v1.end());

std::move and std::copy operate on elements, not containers. You have to mutate the container separately. For example, to move the first 17 elements of v1 into a new vector v2:
std::vector<Foo> v1, v2;
// populate v1 with at least 17 elements...
auto it = std::next(v1.begin(), 17);
std::move(v1.begin(), it, std::back_inserter(v2)); // ##
v1.erase(v1.begin(), it);
After line ##, the first 17 elements of v1 are still there, but they've been "moved-from", so they're in an indeterminate state.

The std::move lets you move the objects, as opposed to copying them, allowing for a potentially faster execution speed. The savings may be even greater when you move a range of values. However, when you do move a range from a container, the container still holds the places that were once occupied by these values.
You need to resize the container manually to remove these placeholders if you want to get rid of them (you don't have to, in case you would prefer reusing these container spots for other elements). One way to do it is to call vector::erase on the same range that you moved out of the container.

You can't move elements from one vector to another the way you are thinking about; you will always have to erase the element positions from the first vector.
If you want to change all the elements from the first vector into the second and vice versa you can use swap.
If you want to move the same amount of elements between two vectors, you can use swap_ranges

Related

Moving elements between two std::vectors without making copies [duplicate]

How can I move some elements from first vector to second, and the elements will remove from the first?
if I am using std::move, the elements not removed from first vector.
this is the code I wrote:
move(xSpaces1.begin() + 7, xSpaces1.end(), back_inserter(xSpaces2));
Resurrecting an old thread, but I am surprised that nobody mentioned std::make_move_iterator combined with insert. It has the important performance benefit of preallocating space in the target vector:
v2.insert(v2.end(), std::make_move_iterator(v1.begin() + 7),
std::make_move_iterator(v1.end()));
As others have pointed out, first vector v1 is now in indeterminate state, so use erase to clear the mess:
v1.erase(v1.begin() + 7, v1.end());
std::move and std::copy operate on elements, not containers. You have to mutate the container separately. For example, to move the first 17 elements of v1 into a new vector v2:
std::vector<Foo> v1, v2;
// populate v1 with at least 17 elements...
auto it = std::next(v1.begin(), 17);
std::move(v1.begin(), it, std::back_inserter(v2)); // ##
v1.erase(v1.begin(), it);
After line ##, the first 17 elements of v1 are still there, but they've been "moved-from", so they're in an indeterminate state.
The std::move lets you move the objects, as opposed to copying them, allowing for a potentially faster execution speed. The savings may be even greater when you move a range of values. However, when you do move a range from a container, the container still holds the places that were once occupied by these values.
You need to resize the container manually to remove these placeholders if you want to get rid of them (you don't have to, in case you would prefer reusing these container spots for other elements). One way to do it is to call vector::erase on the same range that you moved out of the container.
You can't move elements from one vector to another the way you are thinking about; you will always have to erase the element positions from the first vector.
If you want to change all the elements from the first vector into the second and vice versa you can use swap.
If you want to move the same amount of elements between two vectors, you can use swap_ranges

What is the best way to move a range from a container to another? [duplicate]

How can I move some elements from first vector to second, and the elements will remove from the first?
if I am using std::move, the elements not removed from first vector.
this is the code I wrote:
move(xSpaces1.begin() + 7, xSpaces1.end(), back_inserter(xSpaces2));
Resurrecting an old thread, but I am surprised that nobody mentioned std::make_move_iterator combined with insert. It has the important performance benefit of preallocating space in the target vector:
v2.insert(v2.end(), std::make_move_iterator(v1.begin() + 7),
std::make_move_iterator(v1.end()));
As others have pointed out, first vector v1 is now in indeterminate state, so use erase to clear the mess:
v1.erase(v1.begin() + 7, v1.end());
std::move and std::copy operate on elements, not containers. You have to mutate the container separately. For example, to move the first 17 elements of v1 into a new vector v2:
std::vector<Foo> v1, v2;
// populate v1 with at least 17 elements...
auto it = std::next(v1.begin(), 17);
std::move(v1.begin(), it, std::back_inserter(v2)); // ##
v1.erase(v1.begin(), it);
After line ##, the first 17 elements of v1 are still there, but they've been "moved-from", so they're in an indeterminate state.
The std::move lets you move the objects, as opposed to copying them, allowing for a potentially faster execution speed. The savings may be even greater when you move a range of values. However, when you do move a range from a container, the container still holds the places that were once occupied by these values.
You need to resize the container manually to remove these placeholders if you want to get rid of them (you don't have to, in case you would prefer reusing these container spots for other elements). One way to do it is to call vector::erase on the same range that you moved out of the container.
You can't move elements from one vector to another the way you are thinking about; you will always have to erase the element positions from the first vector.
If you want to change all the elements from the first vector into the second and vice versa you can use swap.
If you want to move the same amount of elements between two vectors, you can use swap_ranges

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:
While looping through vec1 simply erasing what I need to remove from it:
it = vec1.erase(it)
While looping through vec1 moving the last item to the actual index and poping_back
vec1.at(index) = vec1.back();
vec1.pop_back();
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());
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!
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.
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.
Your attempt #2 suggests that you're not interested in the order of the elements. remove_if will suffer performance problems as it will maintain the order of the items that you don't delete; meaning you could do a substantial number of shifts to maintain this order.
The swapping and popping will suffer the problem that repeatedly popping the back isn't required - it could resize the vector or do other things.
As such, by combining the ideas - of swapping the "last not swapped out" (ie last the first time, 2nd last the 2nd etc) and then at the end erasing the end items once complete; you should have the fastest algorithm.
Some of the comments suggest that a copy is faster than a swap; and while true when doing a single copy; for a vector when you're copying multiple elements multiple times; the swap will be significantly faster.

"Merge" pointer to vector

Sorry if the title is wrong. I am not sure how to describe my problem in a line.
Suppose I have multiple vectors of type cv::Point and that at each iteration I am to create a new vector that will hold the concatenation of 2 other vectors, what is the most efficient way of doing so? In the example below, vector V4 will hold the elements of vector V1 and V2, and V5 will hold V4 and V3.
I would not like to copy the elements over. It would be better if I could get a single iterator that points to V1 and V2 because the vectors get really large over time.
I have tried this from What is the best way to concatenate two vectors? but im not sure if there are faster options. I also used the boost:join function but it seems to be much slower.
Ideally, this copy/move operation is time constant because the entire application revolves around it.
AB.reserve( A.size() + B.size() ); // preallocate memory
AB.insert( AB.end(), A.begin(), A.end() );
AB.insert( AB.end(), B.begin(), B.end() );
You might want to consider doing something at least vaguely like a deque is normally implemented--essentially a vector of pointers to vectors, that keeps track of the bounds on each component vector, so it can find the appropriate vector, the adjust the index for the vector that contains the element you need.
Depending on the situation, you might also consider attempting to keep the component vectors equal in size to speed computation of the correct index. If they start out with wildly disparate sizes, this probably won't be worthwhile, but if they're close to the same, it may be worth moving some over from one to the next to equalize their sizes. To facilitate this, you'd want to leave an initially-unused section at the beginning of each vector so you can move some elements from one to the beginning of the next quickly and easily.

Difference between std::remove and erase for vector?

I have a doubt that I would like to clarify in my head. I am aware of the different behavior for std::vector between erase and std::remove where the first physically removes an element from the vector, reducing size, and the other just moves an element leaving the capacity the same.
Is this just for efficiency reasons? By using erase, all elements in a std::vector will be shifted by 1, causing a large amount of copies; std::remove does just a 'logical' delete and leaves the vector unchanged by moving things around. If the objects are heavy, that difference might matter, right?
Is this just for efficiency reason? By using erase all elements in a std::vector will be shifted by 1 causing a large amount of copies; std::remove does just a 'logical' delete and leaves the vector unchanged by moving things around. If the objects are heavy that difference mihgt matter, right?
The reason for using this idiom is exactly that. There is a benefit in performance, but not in the case of a single erasure. Where it does matter is if you need to remove multiple elements from the vector. In this case, the std::remove will copy each not removed element only once to its final location, while the vector::erase approach would move all of the elements from the position to the end multiple times. Consider:
std::vector<int> v{ 1, 2, 3, 4, 5 };
// remove all elements < 5
If you went over the vector removing elements one by one, you would remove the 1, causing copies of the remainder elements that get shifted (4). Then you would remove 2 and shift all remainding elements by one (3)... if you see the pattern this is a O(N^2) algorithm.
In the case of std::remove the algorithm maintains a read and write heads, and iterates over the container. For the first 4 elements the read head will be moved and the element tested, but no element is copied. Only for the fifth element the object would be copied from the last to the first position, and the algorithm will complete with a single copy and returning an iterator to the second position. This is a O(N) algorithm. The later std::vector::erase with the range will cause destruction of all the remainder elements and resizing the container.
As others have mentioned, in the standard library algorithms are applied to iterators, and lack knowledge of the sequence being iterated. This design is more flexible than other approaches on which algorithms are aware of the containers in that a single implementation of the algorithm can be used with any sequence that complies with the iterator requirements. Consider for example, std::remove_copy_if, it can be used even without containers, by using iterators that generate/accept sequences:
std::remove_copy_if(std::istream_iterator<int>(std::cin),
std::istream_iterator<int>(),
std::ostream_iterator<int>(std::cout, " "),
[](int x) { return !(x%2); } // is even
);
That single line of code will filter out all even numbers from standard input and dump that to standard output, without requiring the loading of all numbers into memory in a container. This is the advantage of the split, the disadvantage is that the algorithms cannot modify the container itself, only the values referred to by the iterators.
std::remove is an algorithm from the STL which is quite container agnostic. It requires some concept, true, but it has been designed to also work with C arrays, which are static in sizes.
std::remove simply returns a new end() iterator to point to one past the last non-removed element (the number of items from the returned value to end() will match the number of items to be removed, but there is no guarantee their values are the same as those you were removing - they are in a valid but unspecified state). This is done so that it can work for multiple container types (basically any container type that a ForwardIterator can iterate through).
std::vector::erase actually sets the new end() iterator after adjusting the size. This is because the vector's method actually knows how to handle adjusting it's iterators (the same can be done with std::list::erase, std::deque::erase, etc.).
remove organizes a given container to remove unwanted objects. The container's erase function actually handles the "removing" the way that container needs it to be done. That is why they are separate.
I think it has to do with needing direct access to the vector itself to be able to resize it. std::remove only has access to the iterators, so it has no way of telling the vector "Hey, you now have fewer elements".
See yves Baumes answer as to why std::remove is designed this way.
Yes, that's the gist of it. Note that erase is also supported by the other standard containers where its performance characteristics are different (e.g. list::erase is O(1)), while std::remove is container-agnostic and works with any type of forward iterator (so it works for e.g. bare arrays as well).
Kind of. Algorithms such as remove work on iterators (which are an abstraction to represent an element in a collection) which do not necessarily know which type of collection they are operating on - and therefore cannot call members on the collection to do the actual removal.
This is good because it allows algorithms to work generically on any container and also on ranges that are subsets of the entire collection.
Also, as you say, for performance - it may not be necessary to actually remove (and destroy) the elements if all you need is access to the logical end position to pass on to another algorithm.
Standard library algorithms operate on sequences. A sequence is defined by a pair of iterators; the first points at the first element in the sequence, and the second points one-past-the-end of the sequence. That's all; algorithms don't care where the sequence comes from.
Standard library containers hold data values, and provide a pair of iterators that specify a sequence for use by algorithms. They also provide member functions that may be able to do the same operations as an algorithm more efficiently by taking advantage of the internal data structure of the container.