range-v3 views::drop 和 views::drop_exactly 有什么区别?

What is the difference between range-v3 views::drop and views::drop_exactly?

谁能解释一下 range-v3 的视图适配器 dropdrop_exactly 之间的区别?

我观察到的一个区别是,如果通过管道传输到这些视图的范围内的元素数量少于视图适配器的参数,drop 似乎做对了,而drop_exactly 似乎调用了 UB。

当参数小于通过管道传输到这些视图的范围内的元素数时,它们的工作方式似乎相同:

#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
}

这是 code

来自 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.

虽然 drop 的文档指出:

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.

强调


猜测 drop_exactly 避免了边界检查,因此有可能以 运行 过去的代价为代价稍微提高性能piped-in 容器的 end,而 drop 显然会执行边界检查以确保您不这样做。

这和你看到的一致。如果您打印 std::vectorbegin()+7begin()+5(又名 end())的内容,并且中止条件是使用 != 而不是 <,那么你将继续打印位于向量分配的 space 中的垃圾数据,直到在某个时候你 运行 超过分配的块并且操作系统介入并对你的二进制文件进行段错误。

因此,如果您知道 容器中有您希望删除的条目,请使用更快的 drop_exactly,否则使用 drop