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

时间:2019-04-09 08:18:02

标签: c++ string c++11 language-lawyer

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

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

期望:pos <= size()。

     

返回:如果pos

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

不幸的是,我无法对此做出解释,如果它是未定义行为,那就更好了。

有人可以解释其背后的原理吗?

4 个答案:

答案 0 :(得分:39)

您必须考虑完整的规格。

首先:

  

期望:pos <= size()。

如果您不遵循前提条件,则无论如何您都有不确定的行为。现在...

  

返回:如果pos

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

PS:人们可能会认为,要实施该规范,operator[]必须检查pos == size是否。但是,如果基础字符数组在字符串末尾有charT(),则基本上可以免费获得所描述的行为。因此,实际上与对数组的“常规”访问似乎有点不同。

答案 1 :(得分:22)

陈述1是陈述2的前提:

  
      
  1. 预期:pos <= size()

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

         

    否则( 所以这里唯一可行的可能性是pos == size() ),返回对值为{{ 1}}(charT ),将对象修改为charT()以外的任何值都会导致未定义的行为。

  4.   

'\0'基本上指向空终止符。您可以读写,但是只能在其中写入charT()

答案 2 :(得分:15)

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

答案 3 :(得分:2)

除了前面的答案外,请查看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指出),它仅在调试模式下才被触发,而第二种则总是抛出,而与库的构建选项无关。 / p>