C++ 在迭代器的计算中,如果使用begin()之前或end()之后的迭代器作为操作数,其行为是否已定义?

C++ 在迭代器的计算中,如果使用begin()之前或end()之后的迭代器作为操作数,其行为是否已定义?,c++,C++,我尝试了一个实验: #include <iostream> #include <vector> int main(void) { std::vector<int> a{1, 2, 3}; std::vector<int>::iterator b = a.begin(); std::vector<int>::iterator c = a.end(); std::vector<int>::iterator d

我尝试了一个实验:

#include <iostream>
#include <vector>

int main(void) {
  std::vector<int> a{1, 2, 3};
  std::vector<int>::iterator b = a.begin();
  std::vector<int>::iterator c = a.end();
  std::vector<int>::iterator d = b - 1;
  std::vector<int>::iterator e = c + 1;
  std::cout << true << std::endl;
  std::cout << (d < b) << std::endl;
  std::cout << (e > c) << std::endl;
  return 0;
}

但是有人告诉我deque的行为没有定义,你怎么看?谢谢大家!

正如您所怀疑的,使用d或e的行为尚未定义


您可以测试c是否与a.end相等,但请注意,任何对它的解引用行为都是未定义的。

正如您所怀疑的,使用d或e的行为都是未定义的

您可以测试c是否与a.end相等,但是请注意,任何取消引用的行为都是未定义的。

不仅对于deque,而且对于任何容器都是未定义的,但是只有随机访问容器才允许编译。

不仅对于deque,而且对于任何容器都是未定义的,只有随机访问容器才允许编译尽管如此。

没有

d和e都是奇异迭代器,因为它们既不指向序列中的元素,也不指向经过伪元素结尾的元素

你几乎不能用单一迭代器做任何事情:

[C++11:24.2.1/5]:正如指向数组的常规指针保证有一个指针值指向数组的最后一个元素一样,对于任何迭代器类型,都有一个迭代器值指向对应序列的最后一个元素。这些值被称为超过结束值。定义了表达式*i的迭代器i的值称为可取消引用。库从不假定超过的结束值是可取消引用的。迭代器还可以具有与任何序列都不关联的奇异值。[示例:在使用int*x;声明未初始化的指针x之后,必须始终假定x具有指针的奇异值。-结束示例]大多数表达式的结果对于奇异值是未定义的;唯一的例外是销毁保存奇异值的迭代器,将非奇异值赋值给保存奇异值的迭代器,以及对于满足DefaultConstructible要求的迭代器,使用值初始化迭代器作为复制或移动操作的源

请特别注意,您不能对它们执行任意比较

我很确定,即使评估a.begin-1或a.end+1都是UB,但我现在找不到任何证据

d和e都是奇异迭代器,因为它们既不指向序列中的元素,也不指向经过伪元素结尾的元素

你几乎不能用单一迭代器做任何事情:

[C++11:24.2.1/5]:正如指向数组的常规指针保证有一个指针值指向数组的最后一个元素一样,对于任何迭代器类型,都有一个迭代器值指向对应序列的最后一个元素。这些值被称为超过结束值。定义了表达式*i的迭代器i的值称为可取消引用。库从不假定超过的结束值是可取消引用的。迭代器还可以具有与任何序列都不关联的奇异值。[示例:在使用int*x;声明未初始化的指针x之后,必须始终假定x具有指针的奇异值。-结束示例]大多数表达式的结果对于奇异值是未定义的;唯一的例外是销毁保存奇异值的迭代器,将非奇异值赋值给保存奇异值的迭代器,以及对于满足DefaultConstructible要求的迭代器,使用值初始化迭代器作为复制或移动操作的源

请特别注意,您不能对它们执行任意比较


我非常确定,即使是对a.begin-1或a.end+1进行评估,也都是UB,但我现在找不到任何证据。

带有随机访问迭代器的容器可能会让您不必比较迭代器,但它肯定不会对非连续容器起作用,如果你试图做任何调用迭代器的去引用的事情,那也将是未定义的。我认为问题不在于对越界迭代器的去引用,而是关于它们的算术运算。自动it=a.end+1;中是否有UB;?需要语言律师@Drop-a.end+1未定义,因为a.end可能位于内存或内存段的末尾。@Drop-首先,加法可能溢出。如果没有,则结果地址可能在为进程分配的空间之外。在地址寄存器中仅保留非法地址的一些硬件陷阱。但是在x86Linux或Windows上,可能没有什么不好的事情发生。只是您的代码编译并给出有意义的结果这一事实并不意味着这不是未定义的行为。未定义意味着任何事情都可能发生。在最坏的情况下,你得到的结果是t

直到有一天你的代码失败并做了一些非常糟糕的事情,你才会想到。带有随机访问迭代器的容器可能会让你不必比较迭代器,但它肯定不会对非连续容器起作用,如果你试图做任何调用迭代器的去引用的事情,那也将是未定义的。我认为问题不在于对越界迭代器的去引用,而是关于它们的算术运算。自动it=a.end+1;中是否有UB;?需要语言律师@Drop-a.end+1未定义,因为a.end可能位于内存或内存段的末尾。@Drop-首先,加法可能溢出。如果没有,则结果地址可能在为进程分配的空间之外。在地址寄存器中仅保留非法地址的一些硬件陷阱。但是在x86Linux或Windows上,可能没有什么不好的事情发生。只是您的代码编译并给出有意义的结果这一事实并不意味着这不是未定义的行为。未定义意味着任何事情都可能发生。在最坏的情况下,你会得到你期望的结果,直到有一天你的代码失败并做了一些非常丑陋的事情。去引用在哪里?还没有,我怎么敢建议OP会想到这样做:-当然我没有提到任何去引用,我只是问迭代器的计算。解引用在哪里?还没有,我怎么敢建议OP考虑这样做:-当然我没有提到任何解引用,我只是问迭代器的计算。回答很好。那么算术自动it=a.end+1;?或者更好:it-1==a.end?@Drop:it呢?它有定义吗?我们是否保证在加上然后减去相同的整数值后返回a.end?@Drop:我在回答中提到了这一点。@Drop是指针的未定义行为参见标准5.7.4,对于标准的容器容器,我在标准中实际上找不到任何东西,但是它没有定义,它是我可以得到的最好的C++标准库的NICOLAI JOUTITY的引用。那么算术自动it=a.end+1;?或者更好:it-1==a.end?@Drop:it呢?它有定义吗?我们是否保证在加上然后减去相同的整数值后返回a.end?@Drop:我在回答中提到了这一点。@Drop是指针的未定义行为参见标准5.7.4,对于标准的容器容器,我在标准中实际上找不到任何东西,但是它没有定义,它是我可以得到的最好的C++标准库。
1
1
1