非取消引用的迭代器是否超过了“一个过去的末端"?数组未定义行为的迭代器?

鉴于 int foo[] = {0, 1, 2, 3}; 我想知道指向一个过去的末端"的迭代器是否无效.例如:auto bar = cend(foo) + 1;

Given int foo[] = {0, 1, 2, 3}; I want to know if iterators that point past the "one past-the-end" are invalid. For example: auto bar = cend(foo) + 1;

在 Stack 中有大量的抱怨和警告说这是未定义的行为" 这样的溢出问题:c++ iterator + integer when past-end-iterator 的结果是什么? 不幸的是,唯一的来源是挥手.

There are a ton of complaints and warnings that this is "undefined behavior" in Stack Overflow questions like this: c++ what's the result of iterator + integer when past-end-iterator? Unfortunately the only source is hand waving.

我在购买时遇到了越来越多的麻烦,例如:

I'm having more and more trouble buying that, for example:

int* bar;

未初始化,但肯定不会调用未定义的行为,并且经过足够的尝试,我确信我可以找到一个实例,其中未初始化的 bar 中的值与 cend 具有相同的值(foo) + 1.

Is uninitialized, but certainly does not invoke undefined behavior, and given enough tries I'm sure I could find an instance where the value in this uninitialized bar had the same value as cend(foo) + 1.

这里最大的困惑之一是我不是询问解除引用cend(foo) + 1.我知道这将是未定义的行为,标准禁止这样做.但是这样的答案:https://stackoverflow不回答问题.

One of the big confusions here is that I am not asking about dereferencing cend(foo) + 1. I know that would be undefined behavior and the standard forbids it. But answers like this: https://stackoverflow.com/a/33675281/2642059 which cite only that dereferencing such an iterator is illegal do not answer the question.

我也知道 C++ 只保证 cend(foo) 有效,但它可能是 numeric_limits::max(),在在这种情况下 cend(foo) + 1 会溢出.我对这种情况不感兴趣,除非它在标准中被称为我们不能让迭代器超过一个过去的结束"的原因.我知道 int* 实际上只是保存一个整数值,因此会溢出.

I also know that C++ only guarantees that cend(foo) will be valid, but it could be numeric_limits<int*>::max(), in which case cend(foo) + 1 would overflow. I'm not interested in that case unless it is called out in the standard as the reason we can't have an iterator past the "one past-the-end". I know that int* really just holds an integer value, and as such is subject to overflow.

我想引用一个可靠来源的引文,指出将迭代器移动到one past-the-end"元素之外是未定义的行为.

推荐答案

是的,如果你形成这样的指针,你的程序会有未定义的行为.

Yes, your program has undefined behaviour if you form such a pointer.

这是因为您可以这样做的唯一方法是增加一个有效指针,使其越过它所指向的对象的边界,这是一个未定义的操作.

That's because the only way you can do so is to increment a valid pointer past the bounds of the object it points inside, and that is an undefined operation.

[C++14: 5.7/5]: 当一个整数类型的表达式被添加到指针或从指针中减去时,结果的类型为指针操作数.如果指针操作数指向数组对象的一个??元素,并且数组足够大,则结果指向一个元素与原始元素的偏移量,使得结果和原始的下标不同数组元素等于整数表达式.换句话说,如果表达式 P 指向数组对象的第 i 个元素,则表达式 (P)+N 等价地,N+(P)) 和 (P)-N(其中 N 的值为 n)指向,分别是数组对象的第 i + n 个和第 i - n 个元素,前提是它们存在.此外,如果表达式 P 指向数组对象的最后一个元素,则表达式 (P)+1 指向数组对象的最后一个元素,如果表达式 Q 指向数组对象的最后一个元素,表达式 (Q)-1 指向数组对象的最后一个元素.如果指针操作数和结果都指向同一个数组对象的元素,或者超过数组对象的最后一个元素,则计算不应产生溢出;否则,行为未定义.

[C++14: 5.7/5]: When an expression that has integral type is added to or subtracted from a pointer, the result has the type of the pointer operand. If the pointer operand points to an element of an array object, and the array is large enough, the result points to an element offset from the original element such that the difference of the subscripts of the resulting and original array elements equals the integral expression. In other words, if the expression P points to the i-th element of an array object, the expressions (P)+N equivalently, N+(P)) and (P)-N (where N has the value n) point to, respectively, the i + n-th and i ? n-th elements of the array object, provided they exist. Moreover, if the expression P points to the last element of an array object, the expression (P)+1 points one past the last element of the array object, and if the expression Q points one past the last element of an array object, the expression (Q)-1 points to the last element of the array object. If both the pointer operand and the result point to elements of the same array object, or one past the last element of the array object, the evaluation shall not produce an overflow; otherwise, the behavior is undefined.

未初始化的指针不是一回事,因为除了声明它(这显然是有效的)之外,您从未做过任何事情来获取"该指针.但是你甚至不能评估它(不是取消引用 — evaluate)而不用未定义的行为来灌输你的程序.直到您为其分配了一个有效值.

An uninitialised pointer is not the same thing because you never did anything to "get" that pointer, other than declaring it (which is obviously valid). But you can't even evaluate it (not dereference — evaluate) without imbuing your program with undefined behaviour. Not until you've assigned it a valid value.

作为旁注,我不会将这些过去的"迭代器/指针称为 C++ 中的一个术语,专门表示one 过去的"迭代器/指针,这是有效的(例如 cend(foo) 本身).你已经waaaay结束了.;)

As a sidenote, I would not call these "past-the-end" iterators/pointers, a term in C++ which specifically means the "one past-the-end" iterator/pointer, which is valid (e.g. cend(foo) itself). You're waaaay past the end. ;)

相关文章