对于输入迭代器,为什么a == b并不意味着++ a == ++ b?

Naw*_*waz 14 c++ iterator stl

§24.1.1/ 3来自C++ 03标准读物,

对于输入迭代器,a == b并不意味着++ a == ++ b.(Equality不保证替换属性或引用透明性.)输入迭代器上的算法绝不应该尝试两次通过相同的迭代器.它们应该是单通道算法.值类型T不需要是可分配类型(23.1).这些算法可以通过istream_iterator类与istreams一起用作输入数据的源.

我无法理解上面引文中的粗体文字.任何人都可以帮我理解这个吗?

另外,以下语句(上述引文中的斜体文字)是什么意思?它是如何与a==b++a==++b表情?

平等并不保证替代财产或参考透明度.

Ste*_*sop 9

对于输入迭代器,递增迭代器会使同一迭代器的副本无效.

所以:

auto a = istream_iterator<whatever>(something);
auto b = a;
a == b; // true
++a;    // b is now invalid
++b;    // undefined behavior, I think, but in any case not guaranteed to
        // result in anything sensible.
Run Code Online (Sandbox Code Playgroud)

所以当然++a == ++b不能保证.也就是说,a == b并不意味着++a == ++b.

我认为"替换属性"的意思是"你对值的a所做的任何事情都与使用相同的值进行相同的结果b",或类似的 - 它可能引用了各种版本的替换,但是这些行中的某些东西.我觉得在这方面就一定意味着" 后来做同一样b",因为如果a == b我没有做任何事情还无效,那么它并不重要的ab我用,它们指的是同一个点的流.但是当我增加时,我必须选择一个而失去另一个,因此难度增加++a == ++b.

"参照透明度"意味着不同的对象是独立的,即它们不是彼此的引用/指针或别名.结合"替代财产",这意味着:

后来?由于操作没有全局副作用,因此没有更早或更 .如果你不能替代"以后"那么你就无法替代

输入迭代器以相同的顺序通常引用相同的"实际数据",如文件句柄或其他,它本身包含可变状态.由于a并且b引用相同的文件句柄,并且它们的值取决于其状态,因此您没有参照透明度.这种缺乏是替代失败的原因.

前向迭代器通常引用相同的底层数据(如容器),但只要你以只读方式使用它们(并且不以其他方式修改容器),它们就不会背叛这个事实,至少在你之前开始比较它们返回的值的地址.因此,它们对自己的值有一种有限的引用透明,输入迭代器则没有.他们仍然引用自己,所以他们提到的东西仍然是别名.


Kon*_*lph 6

正如解释所说:"它们应该是单通算法."

关键是输入流上的迭代器表示瞬态.迭代器更改后,该状态不再存在; 表示该状态的所有其他迭代器都将失效:一旦递增a,迭代器b将变为无效.


Mat*_* M. 4

所指的属性有:

替代性

对于任何量 a 和 b 以及任何表达式 F(x),如果 a = b,则 F(a) = F(b)(如果任一方都有意义,即格式良好)。

参考透明度

非正式地,这意味着值和对该值的引用之间没有区别(因此创建了该术语)。

在命令式编程中,这是一个很难理解的概念,因为我们习惯于修改变量。Rick Hickey(Clojure 背后)对身份和状态之间的区别进行了精彩的演讲,可能会对您有所帮助。它的要点是变量是一个身份。在任何时间点,身份都指一个国家。状态永远不会改变,但是身份可以更改以引用另一个状态。

输入迭代器

替换属性违规在这里是“明显的”,如果我们F(x)在上面定义为++x,那么如果输入迭代器验证了替换属性,则以下内容将成立a == b => ++a == ++b

然而,事实并非如此,因为递增输入迭代器可能会使来自同一源的所有其他输入迭代器无效。从 n3290 中的表 107(第 831 页,就在您引用的段落上方):

++r

pre: r 是可解引用的。

post: r 是可解引用的或者 r 是尾部的。

post:r 先前值的任何副本不再需要可取消引用或位于 == 的域中。

也就是说,当我们执行 时++a,thenb可能会变得无效,因此++b本身将是未定义的行为。

这是对 的直接违反++a == ++b,因此替代性质不成立。

参考透明度在这里更加明显。如果输入迭代器是引用透明的,则意味着它们与它们指向的值是不可区分的。显然情况并非如此,因为应用++不会增加值,而是增加迭代器。