我正在研究顺序容器库,这让我开始思考。
我理所当然地认为,每个容器,除了特殊情况(例如forward_list)(在一个方向上都是不可能的)外,都完全支持迭代器算法。相反,我只是发现通用容器仅支持一组非常特定的操作:*和->(出于明显的原因),前后递增和递减(不能对后递差100%把握)以及相等/不相等关系运算符。对于向量,字符串和双端队列,保留了更复杂的算法。
我不明白这个限制。是什么原因导致我们被禁止(例如,在两个迭代器之间进行减法或向迭代器添加int)?毕竟,如果我们可以使用前/后递增/递减运算,即使效率很低,我们也可以轻松地通过使用整数计数器重复迭代这些操作来实现加法和减法。
答案 0 :(得分:6)
std::distance
和std::advance
提供了您提到的缺失的低效率操作。 (出于更微妙的原因,还有std::prev
和std::next
。)
不要求所有迭代器或至少所有双向迭代器支持operator+=
之类的原因是为了警告用户,他们做的事情效率不如预期。可以很容易地在循环中编写类似*(iter+offset)
的内容,然后将容器类型从std::vector
更改为std::set
,而不会注意到您不小心将O(n)
操作成O(n^2)
。
答案 1 :(得分:2)
您在问题中提到了原因:
...即使效率低下...
这是一个很好的设计,不要在运算符中执行计算复杂的操作(通常是线性的或更差的操作)。此设计允许API的用户假定加法和减法操作具有恒定的复杂性,而无需了解该操作的规范。如果这样的假设是错误的,那么程序员可能会轻易地结束编写渐进复杂性比其预期的糟糕的程序。
此类线性运算以std::next
,std::distance
等形式存在。程序员在不知道该函数规格的情况下不会(或不应该)对函数调用的复杂性进行假设。
如果您不同意标准库的设计,则可以编写迭代器适配器,以添加缺少的运算符重载,并加以使用。