STL中“结束”指针的非常量的基本原理

时间:2014-12-25 20:52:58

标签: c++ stl const

为什么STL的原型功能如此

template <class RandomAccessIterator>
void sort (RandomAccessIterator first, RandomAccessIterator last);

而不是

template <class RandomAccessIterator,ConstRandomAccessIterator>
void sort (RandomAccessIterator first, ConstRandomAccessIterator last);

我们绝不能写入last所代表的元素。然而,库要求函数将结束迭代器作为非常量返回为 very 简单数组类:

T* Container::end()
    {
    return begin+N; //I will screw up the heap if I ever wrote to the address returned here!
    }

而不是正式的正确

const T* Container::end() const
    {
    return begin+N;
    }

2 个答案:

答案 0 :(得分:2)

STL在一个范围的开头和结尾使用一个迭代器类型的主要原因似乎主要是创作者的设计偏好,主要是Alexander Stepanov。第二个原因是STL在没有处理不同的开始和结束迭代器的情况下开始时的复杂性足够复杂。

因为,有很多关于算法的使用的知识,重新考虑开始和结束迭代器是否应该总是使用相同的类型,尽管可能不是你引用的原因:使结束迭代器引用成为一个常量对象真的很有帮助,因为你既不会阅读也不会写它。此外,对于双向迭代器,使结束只读是非常不利的,因为必须使用start迭代器遍历序列以构建可写的结束迭代器(对于随机访问迭代器,您可以在恒定时间内获得结束迭代器)从开始迭代器开始,即它不是一个大问题。)

请注意,仅为结束迭代器使用不同的推导类型实际上会创建大量的灵活性,这不仅仅是创建迭代器的只读版本。要将const添加到begin的迭代器类型中,请使用

中的某些内容。
template <typename RndIt>
void sort(RndIt begin, typename iterator_traits<RndIt>::const_iterator);

当然,现在还没有工作,如上所述,这将是一个坏主意:你绝对希望能够使用两个迭代器来编写算法,尽管你是这样的。显然不是通过结束迭代器写的。

使结束迭代器成为另一种类型的原因是,对于输入和转发迭代器,结尾实际上是不可移动的:你不能移动它而不会超出算法已知的结束而且没有办法把它向后移动因此,它实际上只是一个端点而不是迭代器。给端点提供不同的类型可以使算法的使用更加高效,并且创建新的迭代器更简单。有关此推理线的更多详细信息,请参阅此主题的Eric Niebler's blogs

答案 1 :(得分:0)

std::prev(it);

是与it相同类型的迭代器。如果end()const_iterator而不是iterator,则无效。

在许多算法中,有充分的理由允许使用Sentinel类型代替范围的end()的迭代器类型,但也有充分的理由不允许它们。

此时std库只是假设您的beginend迭代器将是相同的类型,对于大多数容器来说这是合理的。

有一些建议正在分解开始和结束迭代器的类型,这将允许前端迭代器上的const,并允许一些其他优化(如标准库算法中的有效空终止迭代)。 / p>