web-dev-qa-db-ja.com

文字列の位置がそのサイズより大きいstd :: stringの要素にアクセスします

Std :: stringの場合、_(element position) == (size of string)_である要素にアクセスすると、規格は、値charT()を持つタイプcharTのオブジェクトへの参照を返すと規定しています。

_const_reference operator[](size_type pos) const;
reference       operator[](size_type pos);
_

予想:pos <= size()。

戻り値:pos <size()の場合、*(begin()+ pos)。それ以外の場合は、値がcharT()のcharT型のオブジェクトへの参照を返します。オブジェクトをcharT()以外の値に変更すると、動作が未定義になります。

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

残念ながら私はこれについて理由を立てることができませんでした。それが未定義の動作であったならばそれはより良かったでしょう。

誰かがこの背後にある理論的根拠を説明できますか?

36
cpp_enthusiast

完全な仕様を考慮する必要があります。

まず第一に:

予想:pos <= size()。

前提条件に従わない場合は、いずれにしても未定義の動作になります。さて...

戻り値:pos <size()の場合、*(begin()+ pos)。それ以外の場合は、値がcharT()のcharT型のオブジェクトへの参照を返します。オブジェクトをcharT()以外の値に変更すると、動作が未定義になります。

「それ以外の」が言及する唯一の(有効な)ケースは、pos == size()の場合です。そして、それはおそらくアクセス可能な_some_string[size]_要素を持つC文字列の動作をエミュレートすることです。 charT()は通常_'\0'_であることに注意してください。

PS:仕様を実装するには、_operator[]_が_pos == size_かどうかを確認する必要があると考える人もいるかもしれません。ただし、基になる文字配列の文字列の末尾にcharT()がある場合は、基本的に無料で説明されている動作が得られます。したがって、配列への「通常の」アクセスと少し異なるように見えるのは、実際にはそれだけです。

39

ステートメント1は、ステートメント2の前提条件です。

  1. 期待されるもの:pos <= size()

  2. 戻り値:*(begin() + pos) if pos < size()

    そうでない場合(なので、ここで実行可能な唯一の可能性はpos == size())であり、オブジェクトの参照を返しますタイプcharTと値charT()ie _'\0'_)、ここでオブジェクトをcharT()以外の値に変更すると、未定義の動作。

str[str.size()]は、基本的にnull終了文字を指します。読み書きはできますが、_'\0'_のみを書き込むことができます。

22
rustyx

演算子はpossize()以下であることを期待しているので、それが小さくない場合、等しいことが期待されます。

15
Yola

前の回答に加えて、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に感謝)がありますが、ライブラリのビルドオプションに関係なく、2番目は常にスローされます。

2
KostasRim