在 C++11 及更高版本中,std::string::operator[] 是否进行边界检查?

In C++11 and beyond does std::string::operator[] do bounds checking?

我多次看到 std::string::operator[] 不做任何边界检查。即使 What is the difference between string::at and string::operator[]? 在 2013 年被问到,答案也说 operator[] 不做任何边界检查。

我的问题是,如果我查看 [[=​​31=]] 中的标准(在本例中为 draft N3797),我们有

const_reference operator[](size_type pos) const;
reference operator[](size_type pos);
  1. Requires: pos <= size().
  2. Returns: *(begin() + pos) if pos < size(). Otherwise, returns a reference to an object of type charT with value charT(), where modifying the object leads to undefined behavior.
  3. Throws: Nothing.
  4. Complexity: constant time.

这让我相信 operator[] 必须进行某种边界检查以确定它是否需要 return 字符串元素或默认值 charT。这个假设是否正确,现在需要 operator[] 进行边界检查?

http://en.cppreference.com/w/cpp/string/basic_string/operator_at

Returns a reference to the character at specified location pos. No bounds checking is performed.

(强调我的)。

如果你想要边界检查,使用std::basic_string::at

标准暗示实现需要提供边界检查,因为它基本上描述了未经检查的数组访问的作用。

如果您在范围内访问,则已定义。如果你走出去,你会触发未定义的行为。

这个标准容器的运算符模拟普通数组的运算符[]的行为。所以它不做任何检查。然而在调试模式下,相应的库可以提供这种检查。

如果要检查索引,请改用成员函数 at()

operator[] has do some sort of bounds checking to determine...

不,不是。前提条件

Requires: pos <= size().

它可以假设它总是可以return字符串的一个元素。如果不满足此条件:未定义的行为。

operator[] 可能只会将指针从字符串的开头增加 pos。如果字符串更短,那么它只是 returns 对字符串后面数据的引用,无论它可能是什么。就像简单 C 数组中的经典越界。

为了完善 where pos == size() 的情况,它可以在其内部字符串数据的末尾分配一个额外的 charT。因此,仅在不进行任何检查的情况下增加指针,仍会提供规定的行为。

措辞有点乱,仔细研究就会发现其实很准确。

上面写着:

  • 前提是 [] 的参数要么是 = n 要么是 < n.
  • 假设满足前提条件:
    • 如果它是 < n,那么您会得到您要的字符。
    • "Otherwise"(即如果它是 n)那么你得到 charT()(即空字符)。

但是当你打破先决条件时没有定义规则,并且可以隐式满足对 = n 的检查(但没有明确要求be) 通过在位置 n.

实际存储一个 charT()

因此实现不需要执行任何边界检查……而常见的不需要。

首先,有一个requires子句。如果您违反了 requires 子句,您的程序将以未定义的方式运行。即pos <= size().

所以语言只定义了在那种情况下会发生什么。

下一段指出,对于 pos < size(),它 returns 是对字符串中元素的引用。对于 pos == size(),它 returns 对默认构造的 charT 的引用,其值为 charT().

虽然这看起来像是边界检查,但实际上实际发生的是 std::basic_string 分配了一个比要求的大一个缓冲区,并用 charT() 填充最后一个条目。然后[]简单地做指针运算。

我试图想出一种方法来避免这种实现。虽然标准没有强制要求,但我无法说服自己存在替代方案。 .data() 有一些令人讨厌的东西,使得很难避免使用单个缓冲区。