Closed6

std::stringのお尻について

onihusubeonihusube

std::stringのオブジェクトをstrとすると

  • *(str.date() + str.size())\0
  • *str.end()は未定義動作。\0が帰る保証が無い。
  • str[str.size()]\0。書き換えなければ未定義動作にならない。
onihusubeonihusube

std::stringの有効範囲は、[basic.string.general]/3によると。

In all cases, [data(), data() + size()] is a valid range, data() + size() points at an object with value charT() (a “null terminator”), and size() <= capacity() is true.

  • std::stringは文字列終端保証がある。
  • ポインタとして終端要素(str.data() + str.size())にアクセスすると\0が得られる。
onihusubeonihusube

std::stringのイテレータ範囲は文字列終端(\0)を含まない。

そして、その終端イテレータのデリファレンス(*str.end())は未定義動作となる。

Returns an iterator to the character following the last character of the string. This character acts as a placeholder, attempting to access it results in undefined behavior.

  • basic_stringクラスのイテレータ範囲は、ヌル文字(\0)終端ではない
  • この関数によって返されるイテレータは、*thisが保持するいずれの要素も参照しない。その指す先は、不正な範囲となるだろう

規格の記述としては

Returns: An iterator which is the past-the-end value.

とだけあるが、イテレータ要件によってpast-the-end valueを指すイテレータが逆参照可能(dereferenceable)では無いことが示されており、これによって*str.end()が未定義動作となる

Just as a regular pointer to an array guarantees that there is a pointer value pointing past the last element of the array, so for any iterator type there is an iterator value that points past the last element of a corresponding sequence. Such a value is called a past-the-end value. Values of an iterator i for which the expression *i is defined are called dereferenceable. The library never assumes that past-the-end values are dereferenceable.

onihusubeonihusube

添字アクセス([])はイテレータによって定義される([string.access]/2

constexpr const_reference operator[](size_type pos) const;
constexpr reference operator[](size_type pos);
Preconditions: pos <= size().
Returns: *(begin() + pos) if pos < size(). Otherwise, returns a reference to an object of type charT with value charT(), where modifying the object to any value other than charT() leads to undefined behavior.

str[str.size()]は、イテレータ範囲としては終端イテレータに到達しそれをデリファレンスしようとするため未定義動作になりそうだが、ここで特別扱いされて\0が帰ることと書き換えなければ未定義動作にならないことが指定されている。

onihusubeonihusube

つまり?

  • 文字列としてのstd::stringはナル文字(\0)を含んでいる
  • 範囲(range)としてstd::stringはナル文字を含まない
  • イテレータによる操作以外のところでは、endイテレータの位置にナル文字がある事を保証している
  • std::stringのイテレータはポインタとは限らない
このスクラップは2021/12/15にクローズされました