为什么`std::set<T>::end()` 不等于`std::set<T>::iterator{}`?

问题描述

编译这段代码

#include <set>
#include <iostream>

int main(int argc,char * argv[]){
  std::set<int> test;

  std::cout << (test.end() == std::set<int>::iterator{}) << std::endl;
  std::cout << (test.begin() == std::set<int>::iterator{}) << std::endl;
  std::cout << (test.begin() == test.end()) << std::endl;

  return 0;
}

输出(在 gcc 11.1 和 clang 12.0.0 上测试):

0
0
1

...但是,如果我指的是 https://timsong-cpp.github.io/cppwp/n4659/iterators#forward.iterators-2

前向迭代器的 == 域是相同底层序列上的迭代器的域。但是,值初始化的迭代器可以进行比较,并且应该与相同类型的其他值初始化的迭代器进行比较。 [ 注意:值初始化的迭代器的行为就像它们在同一空序列的末尾之后引用一样。 — 尾注 ]

...然后 std::set<int>::iterator{} 是我理解的“值初始化”(注意我使用临时变量得到相同的结果),我希望输出是:

1
1
1

我错过了什么?

解决方法

前向迭代器的 == 域是相同底层序列上的迭代器的域。

所以...可以将来自同一序列的迭代器与 == 进行比较。

但是,值初始化的迭代器可以进行比较,并且应该与相同类型的其他值初始化的迭代器进行比较。

所以...可以用 == 比较两个相同类型的值初始化迭代器。

注意:值初始化的迭代器的行为就像它们在同一空序列的末尾之后引用一样。

注释不是规范性的,但它描述的是对您隐藏了一些空序列,并且值初始化的迭代器表现得好像它们指的是过去这个序列的结束迭代器。

这就是说,就好像标准库为自己实例化了一个 std::set<int> 和一个引用它的 .end() 的值初始化迭代器。

注释与上述一致。如果值初始化的迭代器表现得好像它们都指向同一个序列,那么在同一点,它们将是可比较的并且比较相等。

,

将值初始化的迭代器与序列中的迭代器进行比较是未定义的行为。

“值初始化的迭代器表现得好像它们在同一空序列的末尾之后引用一样”表示它们不能被取消引用或提前。