我在标准中的哪个位置读取或推断出 vector<T>::operator[] 调用 UB 进行越界输入?

Enr*_*lis 0 c++ std undefined-behavior language-lawyer indexoutofboundsexception

cppreference上,我读到了以下内容std::vector<T,Allocator>::operator[]

通过此运算符访问不存在的元素是未定义的行为。

标准草案中是否有类似的句子?或者说,我应该从标准的哪一部分推断出这个东西?

我想如果标准对此只字未提,那就会成为 UB。但我还没有找到任何相关信息std::vector<T,Allocator>::at,所以...

Seb*_*edl 5

它是以一种非常迂回的方式指定的。

首先,成员不是vector直接指定的,而是通用的Sequence。您可以在此处找到规范:http://eel.is/c++draft/sequence.reqmts

一、明显部分:at子句

抛出: out_of_range如果n >= a.size().

这就是at的行为的来源。

至于[],它说:

返回: *(a.begin() + n)

所以效果与该表达式相同。我们需要遵循这个来找到未定义的行为。为此,我们需要查看迭代器要求

现在 C++20 的要求几乎难以理解,但 C++17 的要求仍然存在并且确实适用。所以:

这就是事情变得非常复杂的地方。此时,我们需要将vector::begin和的规范拼凑在一起vector::end,以了解 的重复递增v.begin()最终将(如在v.size()应用程序之后)yield v.end(),它被指定为尾后迭代器。我找不到此类迭代器不可取消引用的明确声明,但http://eel.is/c++draft/iterator.requirements#general-7指定标准库假设它们不可取消引用,在向量的情况下这是真的。

因此,v[v.size()]相当于*(v.begin() + v.size()), 相当于*v.end(), 是未定义的行为。

Andv[v.size()+1]等价于*(v.begin() + v.size() + 1),它等价于*std::next(v.end()),它递增了尾后迭代器,从而导致未定义的行为。

  • @VictorEijkhout不,转换是明确定义的,但结果是`size_type`的最大值,它将是`&gt;=size()`,所以它会抛出。 (2认同)