访问 std::string 中的元素,其中字符串的位置大于其大小

Access elements in std::string where positon of string is greater than its size

本文关键字:位置 大于 字符串 元素 std string 访问      更新时间:2023-10-16

在 std::string 的情况下,如果我们访问一个元素,其中(element position) == (size of string)标准说它返回对值为charT()charT类型的对象的引用。

const_reference operator[](size_type pos) const;
reference       operator[](size_type pos);

期望: pos <= size()。

返回: *(begin() + pos) 如果 pos

http://eel.is/c++draft/strings#string.access-1

不幸的是,我无法对此进行推理,如果它是未定义的行为会更好。

有人可以解释这背后的理由吗?

您必须考虑完整的规格。

首先:

期望: pos <= size()。

如果你不遵循前提条件,无论如何你都会有未定义的行为。现在。。。

返回: *(begin() + pos) 如果 pos

"否则"所指的唯一(有效)情况是当pos == size().这可能是为了模拟具有可以访问的some_string[size]元素的 c 字符串行为。请注意,charT()通常只是''

PS:有人可能会认为要实现该规范,operator[]必须检查是否pos == size。但是,如果底层字符数组在字符串末尾有一个charT(),那么您基本上可以免费获得所描述的行为。因此,看起来与对数组的"通常"访问略有不同,实际上就是这样。

语句 1 是语句 2 的前提条件:

  1. 期望:pos <= size().

  2. 返回:*(begin() + pos) if pos < size().

    否则(所以这里唯一可行的可能性是pos == size()),返回对值为charT()charT类型的对象的引用(''),其中将对象修改为charT()以外的任何值会导致未定义的行为。

str[str.size()]基本上指向 null 终止符字符。您可以读取和写入它,但您只能在其中写入''

运算符期望pos小于或等于size(),因此如果它不小于,则它应该相等。

除了前面的答案之外,请查看libcxx(llvm 实现)定义std::string::operator[]如下:

template <class _CharT, class _Traits, class _Allocator>
inline
typename basic_string<_CharT, _Traits, _Allocator>::const_reference
basic_string<_CharT, _Traits, _Allocator>::operator[](size_type __pos) const _NOEXCEPT
{
_LIBCPP_ASSERT(__pos <= size(), "string index out of bounds");
return *(data() + __pos);
}
template <class _CharT, class _Traits, class _Allocator>
inline
typename basic_string<_CharT, _Traits, _Allocator>::reference
basic_string<_CharT, _Traits, _Allocator>::operator[](size_type __pos) _NOEXCEPT
{
_LIBCPP_ASSERT(__pos <= size(), "string index out of bounds");
return *(__get_pointer() + __pos);
}

看看正确抛出的.at()

template <class _CharT, class _Traits, class _Allocator>
typename basic_string<_CharT, _Traits, _Allocator>::const_reference
basic_string<_CharT, _Traits, _Allocator>::at(size_type __n) const
{
if (__n >= size())
this->__throw_out_of_range();
return (*this)[__n];
}

如您所愿,在第一种情况下,有一个运行时断言(感谢 t.niese 指出),它仅在调试模式下触发,而第二种将始终抛出,无论库的构建选项如何。