Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In-place std::copy_if

Tags:

c++

c++11

stl

It appears to me that std::copy_if would be very useful for filtering containers:

std::vector<int> vec { 1, 2, 3, 4 };
auto itEnd = std::copy_if(vec.begin(), vec.end(), vec.begin(),
                          [](int i) { return i > 2; });
vec.resize(itEnd - vec.begin());

However, std::copy_if is specified that the input and output ranges may not overlap.

Is there an alternative?

like image 658
Manuel Avatar asked Nov 30 '22 02:11

Manuel


1 Answers

copy_if is primarily for copying a range to another range/container I.e. by design, the nature of the algorithm is to copy the elements satisfying some condition to another (non-overlapping) range or to a new container.

remove_if is more appropriate for what you need; it is exactly for filtering out as you expect. However, it only removes the elements by overwriting; the remnants between the old and new ends would be unspecified elements after the function's completion and needs to be manually erased using erase, like so:

std::vector<int> vec { 1, 2, 3, 4 };
vec.erase(std::remove_if(std::begin(vec),
                         std::end(vec),
                         [](int i) { return i <= 2; }),
          std::end(vec));

This is a C++ idiom that goes by the name erase-remove.


Instead of copy_if, if copy was what you wanted, then you've an alternative for overlapping ranges, namely copy_backward; from the documentation

If d_first is within [first, last), std::copy_backward must be used instead of std::copy.

like image 156
legends2k Avatar answered Dec 22 '22 12:12

legends2k