提问人:sbi 提问时间:3/3/2015 更新时间:3/3/2015 访问量:3249
为什么迭代器需要默认可构造
Why do iterators need to be default-constructible
答:
正向迭代器和更强的迭代器需要引用一些外部序列(参见 [forward.iterators]/6,其中说“如果 和 都是可取消引用的,那么当且仅当 和 绑定到同一个对象。a
b
a == b
*a
*b
这意味着它们通常只是其他内容(例如,指向容器中的元素或节点的指针)的轻量级句柄,因此没有理由不要求它们可以默认构造(即使默认构造创建了一个单一的迭代器,在分配新值之前不能用于任何操作)。所有非病态*正向迭代器都可以支持默认构造,并且依赖它使某些算法更容易实现。
仅满足输入迭代器或输出迭代器要求(并且没有更强的)的迭代器可能包含由修改的状态,因此该状态可能无法默认构造。任何只对输入/输出迭代器进行操作的算法都不需要默认构造它们,因此不需要。operator++
- 在这里发现“没有真正的苏格兰人”的论点;)
评论
std::vector<>::iterator
std::search
std::partition_point
std::minmax_element
std::rotate
正向/双向/随机访问迭代器通常可以是指针 - 如果构造和初始化可以保持离域,那么从历史上看,如果代码碰巧是这样,它将有助于从使用指针的代码迁移到迭代器。强制进行更多的大规模更改会让很多人感到沮丧,他们试图将旧代码从显式使用指针迁移到迭代器上。现在更改它会破坏很多代码。
输入和输出运算符通常通过对基础流或其他 I/O 对象的引用最优雅地实现,并且必须在构造时初始化引用。当然,实现可能会被迫推迟这一点,并在内部使用指针,但这肯定会让一些人误入歧途——看起来太像“C”了——所以标准促进引用的使用也就不足为奇了。
评论
std::istream_iterator
std::istream_iterator
输入/输出迭代器:
输入迭代器:一旦 InputIterator i 递增,其先前值的所有副本都可能失效。
输出迭代器:在此操作之后,r 不需要可取消引用,并且不再需要 r 的先前值的任何副本可取消引用或可递增。
如果我们看一下这一点,似乎很明显,这些迭代器被设计为以最简单的方法使用。就像数组索引或简单指针将用于单通道算法一样。 因此,实际上没有必要使用默认构造函数。
但是请注意,仅仅因为从技术上讲不需要默认构造函数,并不能取消您实现它们的资格(如果需要)。
这些是需要默认构造函数的第一级迭代器,但为什么呢?
有很多原因与历史编程原因有关,我相信这在某种程度上都是有效的。在某种程度上,我认为委员会认为需要实现迭代器和随机访问迭代器之间的默认构造,而转发迭代器似乎是最佳选择。
然而,有一个很好的理由:
正向迭代器支持多通道算法,因此要求迭代器的副本在使用/递增迭代器后仍然有效。 如果这些副本仍然有效,则意味着该算法将允许我们将它们“保存”在某个地方。这也意味着我们保存它们的迭代器需要具有默认值/初始值。
考虑:
class MyClass
{
public:
void myFunction(ForwardIterator &i)
{
//do some code here
savedIter = i;
//do some code here
}
private:
ForwardIterator savedIter;
}
根据定义,这是有效的,因为我们被允许将迭代器保存一段时间,因为要求这个迭代器的副本将保持有效。(至少在迭代器指向的数据结构被破坏之前)
但是,要创建此类,ForwardIterator 显然需要一个默认构造函数......
评论
std::vector<T>::iterator it;
std::vector<T>::iterator it = container.begin();
for (; it != container.end(); ++it)