在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
不幸的是,我无法对此做出解释,如果它是未定义行为,那就更好了。
有人可以解释其背后的原理吗?
答案 0 :(得分:39)
您必须考虑完整的规格。
首先:
期望:pos <= size()。
如果您不遵循前提条件,则无论如何您都有不确定的行为。现在...
返回:如果pos
“否则”所指的唯一(有效)情况是pos == size()
时。这可能是为了模拟具有some_string[size]
元素且可以访问的c字符串行为。请注意,charT()
通常只是'\0'
。
PS:人们可能会认为,要实施该规范,operator[]
必须检查pos == size
是否。但是,如果基础字符数组在字符串末尾有charT()
,则基本上可以免费获得所描述的行为。因此,实际上与对数组的“常规”访问似乎有点不同。
答案 1 :(得分:22)
陈述1是陈述2的前提:
预期:
pos <= size()
。返回:
*(begin() + pos) if pos < size()
。否则( 所以这里唯一可行的可能性是
pos == size()
),返回对值为{{ 1}}(即charT
),将对象修改为charT()
以外的任何值都会导致未定义的行为。
'\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>