#include <iostream>
#include <vector>
#include <ranges>
int main()
{
std::vector<int> ints {1, 2, 3, 4, 5};
auto isEven = [] (const auto& element)
{
return element % 2 == 0;
};
auto even = ints | std::views::filter(isEven);
for (auto& element : even)
{
++element;
}
for (const auto& element : ints)
{
std::cout << element << "\n";
}
std::cout << "\n\n";
// Interesting things start further...
for (auto& element : even)
{
++element;
}
for (const auto& element : ints)
{
std::cout << element << "\n";
}
return 0;
}
输出:
1
3
3
5
5
1
4 // Interesting...
3
5
5
您是否注意到第二个输出中的第二个4
?它是如何结束的?这似乎是由于even.begin()
在视图的第一次迭代期间被缓存,因此视图不再正确,因为无论*even.begin()
的实际值如何,它总是以相同的元素开始。
这是否意味着视图不应该被重用呢?但是为什么要缓存呢?
2条答案
按热度按时间kmb7vmvb1#
以这种方式修改
filter_view
的元素被指定为UB。[范围.过滤器.迭代器]/1:
允许修改
filter_view::iterator
表示的元素,但如果结果值不满足筛选 predicate ,则会导致未定义的行为。视图可以重用,但当然需要遵循规则。
qpgpyjmq2#
even.begin()
已在视图的第一次迭代期间被缓存,视图不再正确是的,您理解正确-这就是
filter_view
的工作原理。这是否意味着视图不应该被重用呢?但是为什么要缓存呢?
只要你不修改视图的结果,视图总是可以被重用的。这就是实现缓存的原因。你也可以修改结果,但是你必须小心。对于涉及 predicate 的视图(比如
take_view
),你的修改不允许改变 predicate 的结果。在你的例子中,如果你的修改是: