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

时间:2011-05-10 09:01:54

标签: c++ stl iterator

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

  

对于输入迭代器,a == b并不意味着++ a == ++ b。 Equality不   保证替代财产或   参考透明度。)算法   输入迭代器永远不应该   试图通过相同的   迭代器两次。他们应该是单身   传递算法。值类型T不是   必须是可分配类型   (23.1)。可以使用这些算法   以istream为源头   通过输入数据   istream_iterator类。

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

此外,以下语句(上述引文中的斜体文字)是什么意思?它与a==b++a==++b表达式有什么关系?

  

平等没有   保证替代财产或   参考透明度。

5 个答案:

答案 0 :(得分: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.

所以肯定++a == ++b无法保证。也就是说,a == b并不意味着++a == ++b

我认为“替换属性”的意思是“你使用a的值所做的任何事情都与使用b”或类似的值做同样的结果 - 有各种版本它可能引用的替代,但是沿着这些方向的东西。我认为在这种情况下,它必须意味着“以后b执行相同的操作”,因为如果a == b我还没有做任何无效的事情,那么它就不会我使用ab中的哪一个,它们指的是流中的相同点。但是当我增加时,我必须选择一个而失去另一个,因此++a == ++b存在困难。

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

  

后来?没有之前的或   稍后,因为操作没有全局副作用。如果你不能   替换“稍后”然后你   无法替代

以相同顺序输入迭代器通常引用相同的“实际数据”,如文件句柄或其他任何东西,它本身包含可变状态。由于ab引用相同的文件句柄,并且它们的值取决于其状态,因此您没有引用透明性。缺点是为什么替换失败。

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

答案 1 :(得分:6)

正如解释所说:“它们应该是单通算法。”

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

答案 2 :(得分:3)

提到的属性是:

替代财产

  

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

Referential Transparency

非正式地,它意味着值与对此值的引用之间没有区别(因此该术语是如何创造的)。

在命令式编程中,这是一个难以获得的概念,因为我们习惯于修改变量。 Rick Hickey(在Clojure之后)给出了一个很好的关于distinction between Identity and State的讨论,可以帮助你。它的要点是变量是一个身份。在任何时间点,身份都是指一个国家。国家永远不会改变,但是可以改变身份以引用另一个国家。

输入迭代器

替换属性违规在这里“显而易见”,如果我们在上面定义F(x)来表示++x,那么我们就知道输入迭代器验证了替换属性,以下内容将保留a == b => ++a == ++b

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

  

++ R

     

pre:r是可解除引用的。

     

帖子:r是可解除引用的,或者r是过去的结束。

     

post:不再需要r的先前值的任何副本   可解除引用或属于==。

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

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

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

答案 3 :(得分:2)

输入迭代器定义一个只能读取一次的序列;输入 从键盘或管道将是一个很好的例子。增加一个 istream_iterator有效意味着在istream中进一步阅读, 提取字符,以便在同一个流上提取其他istream_iterator 对于他们的职位将不再有效。想像 一个字符流"abcdefg..."(字母表,总之),有两个 istream_iterator<char>指向'a'。增加一个 它们将导致从流中读取'b',而不是其他 迭代器可以看到它。

答案 4 :(得分:1)

考虑输入迭代器可以连接到从键盘读取的流。增加迭代器意味着读取下一个字符。

同时增加迭代器的副本并不意味着读取相同的字符。