Can someone explain the difference between range-v3's view adaptors drop
and drop_exactly
?
One difference I've observed is that if the number of elements in the range that is piped to these views is less than the argument to the view adaptors, drop
seems to do the right thing, while drop_exactly
seems to invoke UB.
When the argument is less than the number of elements in the range that is piped to these views, they both seem to work the same:
#include <iostream>
#include <vector>
#include <range/v3/all.hpp>
namespace rv = ranges::views;
int main()
{
std::vector<int> v { 1, 2, 3, 4, 5};
for (int i : v | rv::drop(3))
std::cout << i; // prints 45
for (int i : v | rv::drop(7))
std::cout << i; // prints nothing
for (int i : v | rv::drop_exactly(3))
std::cout << i; // prints 45
for (int i : v | rv::drop_exactly(7))
std::cout << i; // prints garbage and crashes
}
Here's the code.
From the documentation for drop_exactly
:
Given a source range and an integral count, return a range consisting of all but the first count elements from the source range. The source range must have at least that many elements.
While the documentation for drop
states:
Given a source range and an integral count, return a range consisting of all but the first count elements from the source range, or an empty range if it has fewer elements.
emphasis added
I'm guessing that drop_exactly
avoids bounds checks and therefore has the potential to be slightly more performant at the cost of maybe running past the end
of the piped-in container, while drop
apparently performs bounds checks to make sure you don't.
This is consistent with what you see. If you print stuff from begin()+7
up to begin()+5
(aka end()
) of a std::vector
, and the abort condition is implemented with !=
instead of <
, then you will continue to print the junk data that sits in the space allocated by the vector until at some point you run over the allocated chunk and the operating system steps in and segfaults your binary.
So, if you know the container to have as many entries as you wish to drop use the faster drop_exactly
, otherwise use drop
.