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

发布于 2024-11-06 07:14:30 字数 472 浏览 1 评论 0原文

C++03 标准中的 §24.1.1/3 读取,

对于输入迭代器,a == b 并不意味着 ++a == ++b。相等并不意味着 保证替代性质或 参考透明度。)算法 输入迭代器不应该 尝试通过相同的 迭代器两次。他们应该是单身 通过算法。值类型 T 不是 需要是可分配类型 (23.1)。可以使用这些算法 以 istreams 作为源 通过输入数据 istream_iterator 类。

我无法理解上面引文中的粗体文字。谁能帮助我理解这一点?

另外,下面的陈述(上面引用中的斜体文本)是什么意思?它与 a==b++a==++b 表达式有何关系?

平等并不 保证替代性质或 参考透明度。

§24.1.1/3 from C++03 Standard reads,

For input iterators, a == b does not imply ++a == ++b. (Equality does not
guarantee the substitution property or
referential transparency.
) Algorithms
on input iterators should never
attempt to pass through the same
iterator twice. They should be single
pass algorithms. Value type T is not
required to be an Assignable type
(23.1). These algorithms can be used
with istreams as the source of the
input data through the
istream_iterator class.

I couldn't understand the bold text in the above quotation. Can anyone help me understanding this?

Also, what does the following statement (italicized text in the above quotation) mean? How is it related to a==b and ++a==++b expressions?

Equality does not
guarantee the substitution property or
referential transparency.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

苏佲洛 2024-11-13 07:14:30

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

所以:

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 引用相同的文件句柄,并且它们的值取决于其状态,因此您没有引用透明度。这种缺乏就是替代失败的原因。

前向迭代器通常引用相同的底层数据(如容器),但只要您以只读方式使用它们(并且不以其他方式修改容器),它们就不会背叛这一点事实上,至少在您开始比较它们返回值的地址之前是这样。因此,它们自身的值具有有限的引用透明度,而输入迭代器则没有。它们本身仍然是引用,因此它们引用的内容仍然是别名。

For Input Iterators, incrementing an iterator invalidates copies of the same iterator.

So:

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.

So certainly ++a == ++b is not guaranteed. That is, a == b does not imply ++a == ++b.

I think the "substitution property" means "anything you do with the value of a has the same result as doing the same with the value of b", or similar - there are various versions of substitution that it might refer to, but something along those lines. I think in this context it must mean "later doing the same with b", since if a == b and I haven't done anything invalid yet, then it doesn't matter which of a and b I use, they refer to the same point in the stream. But when I increment, I do have to pick one and lose the other, hence the difficulty with ++a == ++b.

"Referential transparency" means that different objects are independent, i.e. they're not references/pointers to or aliases of each other. In combination with "substitution property" this means:

Later? There is no earlier or
later since operations don't have global side-effects. If you can't
substitute "later" then you
can't substitute

Input iterators in the same sequence typically refer to the same "actual data", like a file handle or whatever, which itself contains mutable state. Since a and b refer to the same file handle, and their value is dependent on its state, you don't have referential transparency. This lack is why substitution fails.

Forward iterators typically also refer to the same underlying data (like a container), but as long as you use them read-only (and don't otherwise modify the container), they don't betray this fact, at least not until you start comparing the addresses of the values they return. So they have a limited kind of referential transparency of their own value, that input iterators don't. They're still references themselves, so the things they refer to are still aliased.

锦欢 2024-11-13 07:14:30

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

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

As the explanation says: “They should be single pass algorithms.”

The point is that an iterator on an input stream represents a transient state. Once the iterator is changed, that state no longer exists; all other iterators representing that state are invalidated: once you increment a, the iterator b becomes invalid.

弥枳 2024-11-13 07:14:30

提到的属性有:

替换属性

对于任何量 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时,b可能会变得无效,因此++b本身将是未定义的行为。

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

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

The properties referred to are:

Substitution Property

For any quantities a and b and any expression F(x), if a = b, then F(a) = F(b) (if either side makes sense, i.e. is well-formed).

Referential Transparency

Informally, it means that there is no difference between a value and a reference to this value (thus how the term was coined).

In imperative programming it is a difficult concept to get, because we are used to modify our variables. Rick Hickey (behind Clojure) gives a nice talk about the distinction between Identity and State that may help you. The gist of it is that a variable is an Identity. At any point in time an Identity refers to a State. A State never changes, however an Identity may be altered to refer to another State.

Input Iterators

The substitution property violation is "obvious" here, if we define F(x) in the above to mean ++x, then we have that if input iterators verified the substitution property, the following would hold a == b => ++a == ++b.

This is not true, however, because incrementing an input iterator may invalidate all other input iterators from the same source. From table 107 in n3290 (page 831, just above the paragraph you quoted):

++r

pre: r is dereferenceable.

post: r is dereferenceable or r is past-the-end.

post: any copies of the previous value of r are no longer required either to be
dereferenceable or to be in the domain of ==.

That is, when we perform ++a, then b may become invalid, and therefore ++b itself will be undefined behavior.

This is a direct violation of ++a == ++b, therefore the substitution property does not hold.

The referential transparency is a bit more evident here. If Input Iterators were referentially transparent, it would mean that they would be indifferentiable from the value they point to. Clearly this is not the case, as applying ++ does not increment the value, but the iterator.

感性 2024-11-13 07:14:30

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

Input iterators define a sequence which can only be read once; input
from a keyboard or a pipe would be a good example. Incrementing an
istream_iterator effectively means reading further in the istream,
extracting characters, so other istream_iterator on the same stream
will no longer be valid with regards to their position. Imagine
a stream of characters "abcdefg..." (the alphabet, in sum), with two
istream_iterator<char> pointing to the 'a'. Incrementing one of
them will cause the 'b' to be read from the stream, and no other
iterator can ever see it.

囍孤女 2024-11-13 07:14:30

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

另外,递增迭代器的副本并不意味着读取相同的字符。

Consider that an input iterator could be connected to a stream reading from the keyboard. Incrementing the iterator means reading the next character.

Also incrementing a copy of the iterator does not mean reading the same character.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文