【发布时间】:2020-06-23 22:11:37
【问题描述】:
我尝试实现以下类型的循环缓冲区。
为简单起见,我假设循环缓冲区只是具有RandomAccessIterator 的容器的容器适配器(如std::stack)。容器以某种方式调整大小/填充值,然后放置到适配器中。之后,底层容器的大小不应该改变。
显然c.begin() == c.end() 用于循环缓冲区。某些算法(例如,基于范围的 for 循环)对于循环缓冲区无法按预期工作(而不是 for (;;) 可以使用 assert(!c.empty()); auto beg = std::begin(c), it = beg; do { f(it); } while (++it != beg); 遍历循环缓冲区)。
当我尝试使用std::sort 对循环缓冲区进行排序时,出现了主要问题。从底层容器继承迭代器类别对于循环缓冲区迭代器是不公平的。循环缓冲区的迭代器应该几乎是RandomAccessIterator,但不是严格完全有序的(<、>、<=、>= 未定义)。 std::sort 的实现可以在内部使用operator <(并且确实如此)。
我无法定义自己的迭代器类别(例如,ModularIterator)并将其插入现有类别(例如std::is_base_of_v<std::bidirectional_iterator_tag, my_iterator_tag> 和std::is_base_of_v<my_iterator_tag, std::random_access_iterator_tag>)之间。算法也不是定制点。
我不想将iterator_category 设置为std::bidirectional_iterator_tag,因为std::equal_range 在对数时间内不起作用。
RandomAccessIterator 的严格总排序真的需要在算法中的某个地方还是可以避免?
有没有办法让<algorithm>s 为循环缓冲区工作?
是否在标准中疏忽了没有适合无序迭代器的迭代器类别,可以为O(1) 的任何步骤推进?
【问题讨论】:
-
听起来您希望标准库适应您的迭代器类型。似乎您假设您的迭代器类型基本上是原始指针的别名。您应该忘记这种先入之见,并编写一个与标准库函数兼容的迭代器。通过自己计算迭代器中的实际元素位置来使迭代器随机访问。确保
begin不是end。 -
"显然
c.begin() == c.end()用于循环缓冲区。"这一点都不明显。这是一个错误的实现。 -
@Barry 为什么不正确?标准中是否有禁止声明?
-
因为这是迭代器抽象的工作方式。
c.begin() == c.end()表示一个空范围。仅仅因为你的存储是循环的并不意味着范围是空的——抽象的重点是将算法与存储分开。由您来确保您的迭代器为您的存储做正确的事情(即++i、i == j、*i、i + n、j - i等都是有意义的)。是的,您的迭代器应该是随机访问迭代器(因为这应该是一种廉价的操作)。 -
range-v3 用循环迭代器试验过一次; it was eventually abandoned "as a hopeless bug farm".
标签: c++ algorithm iterator language-lawyer c++20