有人能解释range-v3的视图适配器drop
和drop_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
}
这是代码。
来自drop_exactly
的文档:
给定一个源范围和一个整数,返回一个包含源范围中除第一个计数元素外的所有元素源范围必须至少有那么多元素
而drop
的文档声明:
给定一个源范围和一个整数,返回一个包含源范围中除第一个计数元素外的所有元素中,或空范围,如果元素较少。
emphasis added
我猜drop_exactly
避免了边界检查,因此有可能以超过管道容器的end
为代价稍微提高性能,而drop
显然会执行边界检查以确保不执行边界检查。
这与您所看到的一致。如果打印从begin()+7
到std::vector
的begin()+5
(也称为end()
(的内容,并且中止条件是用!=
而不是<
实现的,那么您将继续打印矢量分配的空间中的垃圾数据,直到在某个时候您运行了分配的块,操作系统介入并分段您的二进制文件。
因此,如果您知道容器具有与您希望删除的条目一样多的条目,请使用更快的drop_exactly
,否则请使用drop
。