I am writing a class which requires highly efficient function for filtering member container (lets say std::vector
). This function should have interface similar to the following:
void filter(std::vector<SomeType>& items, const std::vector<int>& inds);
The function should leave the container items
in the following state:
- items that are pointed to by the index from inds
should be removed
- other items should remain in container keeping initial order.
For simplicity lets assume that inds
is a perfect container with O(1) on every operation and all indices are valid with no duplication.
My idea was to create the second container, reserve required space and then move (through std::move
) every element not indexed by inds
into this new container; and afterwards just swap the old and the new containers.
For example like this:
void filter(std::vector<SomeType>& items, const std::vector<int>& inds)
{
std::vector<SomeType> new_items{};
new_items.reserve( items.size() - inds.size() );
for(size_t i = 0; i < items.size(); ++i)
if( contains( inds, i ) ) // magic O(1) function, never mind
new_items.push_back( std::move( items[i] ) );
items.swap(new_items);
}
My questions are:
1) after using std::move
on some element inside the vector
(or generally any other standard container) will there be any issues like double destructing of these elements?
2) Is there a standard way to do such filtering efficiently?
It's not the container's responsibility to safeguard from issues that might arise from moving. As long as the type of the items moved has a well-defined and correct move constructor / implicit move constructor then moving the items from items
to new_items
is the same as any other move operation; containers don't change this.
In short, this responsibility lays with the class, not the container it's used in.