Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/143.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 为什么迭代器需要是默认可构造的_C++_Stl_Iterator_Language Lawyer_Standard Library - Fatal编程技术网

C++ 为什么迭代器需要是默认可构造的

C++ 为什么迭代器需要是默认可构造的,c++,stl,iterator,language-lawyer,standard-library,C++,Stl,Iterator,Language Lawyer,Standard Library,前向、双向和随机访问类别的迭代器需要是默认可构造的 为什么会这样,为什么输入和输出运算符不必是默认可构造的 前向迭代器和更强的迭代器需要引用某些外部序列(请参见[Forward.iterators]/6,其中表示“如果a和b都是可取消引用的,那么a==b当且仅当*a和*b绑定到同一个对象。”) 这意味着它们通常只是其他对象的轻量级句柄(例如,指向容器中元素或节点的指针),因此几乎没有理由不要求它们可以默认构造(即使默认构造创建了一个单一迭代器,在分配新值之前不能用于任何事情)。所有非病态*前向迭

前向、双向和随机访问类别的迭代器需要是默认可构造的


为什么会这样,为什么输入和输出运算符不必是默认可构造的

前向迭代器和更强的迭代器需要引用某些外部序列(请参见[Forward.iterators]/6,其中表示“如果
a
b
都是可取消引用的,那么
a==b
当且仅当
*a
*b
绑定到同一个对象。”)

这意味着它们通常只是其他对象的轻量级句柄(例如,指向容器中元素或节点的指针),因此几乎没有理由不要求它们可以默认构造(即使默认构造创建了一个单一迭代器,在分配新值之前不能用于任何事情)。所有非病态*前向迭代器都可能支持默认构造,依靠它,一些算法更容易实现

仅满足输入迭代器或输出迭代器要求的迭代器(没有更强大的要求)可能包含由
operator++
修改的状态,因此可能无法默认构造该状态。没有只在输入/输出迭代器上运行的算法需要默认构造它们,因此不需要这样做

  • 在这里找出“没有真正的苏格兰人”的论点;)
前向/双向/随机访问迭代器通常可以是指针-如果构造和初始化可以保持非定域(如果代码恰好是这样的话),那么它在历史上有助于从使用代码的指针迁移到迭代器。强制进行更大规模的更改会使许多试图将旧代码从显式使用指针迁移到迭代器上的人感到沮丧。现在更改它会破坏很多代码

输入和输出运算符通常通过对底层流或其他I/O对象的引用来最优雅地实现,并且必须在构造时初始化引用。当然,实现可能会被迫推迟,并在内部使用指针,但这肯定会让一些人误入歧途——看起来太像“C”——因此,毫不奇怪,该标准促进了引用的使用。

输入/输出迭代器:

:一旦InputIterator i递增,其先前值的所有副本都可能无效

:在此操作之后,r不需要是可取消引用的,并且r的上一个值的任何副本不再需要是可取消引用的或可增加的

如果我们看一下这一点,似乎很清楚,这些迭代器是设计用于尽可能最简单的方法中的。很像一个数组索引或简单指针将用于单次传递算法。 因此,实际上不需要使用默认构造函数

但是请注意,仅仅因为默认构造函数在技术上不是必需的,并不意味着如果您愿意,您就没有资格实现它们

这些是需要默认构造函数的第一级迭代器,但为什么呢

有很多原因与历史编程原因等有关,我相信这些都在某种程度上是正确的。在某种程度上,我认为委员会认为需要实现迭代器和randomAccessIterator之间的默认构造,而前向迭代器似乎是最佳选择

然而,有一个相当好的理由可以解释:

前向迭代器支持多过程算法,因此要求迭代器的副本在迭代器被使用/增加后仍然有效。 如果这些副本仍然有效,这意味着算法将允许我们将它们“保存”到某个地方。这也意味着我们保存它们的迭代器需要有一个默认值/初始值

考虑:

class MyClass
{
 public:
  void myFunction(ForwardIterator &i)
  {
    //do some code here
    savedIter = i;
    //do some code here
  }
 private:
  ForwardIterator savedIter;
}
根据定义,这是有效的,因为我们可以将迭代器保存一段时间,因为要求该迭代器的副本保持有效。(至少在迭代器指向的数据结构被破坏之前)


然而,对于要创建的这个类,ForwardIterator显然需要一个默认构造函数…

可能是因为许多人用它来编写
std::vector::iterator在for循环之外,以避免超出推荐的78个字符的线宽。如果要使用
std::vector::iterator,则它=container.begin()
那么for循环就没有那么性感了:
for(;it!=container.end();++it)
。不幸的是,有些算法的实现方式要求默认的可构造性。原则上,这似乎是避免过早分配的合理要求,但在我看到的示例中,它可以很容易地避免。我最近尝试实现一个迭代器,并要求默认可构造,但不幸的是添加了一个间接级别,否则就没有必要了。因此,我一直在为间接寻址的额外级别付费,我认为这个要求非常不幸,因为它有一个令人讨厌的隐藏成本;他们通常有一个很好的理由。对我来说,这似乎是非常特殊的STL容器。很容易想到一些自定义迭代器,它比
std::vector::iterator
存储更多的状态,并且这种状态也不能凭空创建。为什么输入和输出迭代器不应该是单数的呢?(事实上,流迭代器是默认可构造的。)@MarkRansom注意,SGI STL all迭代器必须是默认可构造的,该标准实际上删除了对输入和输出迭代器的要求。在libstdc++(因此可能也在SGI STL中)中,至少
std::search
std::partition_点
std::minmax_元素
依赖于默认构造正向迭代器<代码>标准::罗塔