§21.4.5 [string.access]
const_reference operator[](size_type pos) const;
reference operator[](size_type pos);
戻り値:
*(begin() + pos)
の場合pos < size()
。charT
それ以外の場合は、 value を持つ型のオブジェクトへの参照を返しますcharT()
。オブジェクトを変更すると、未定義の動作が発生します。
2番目の部分は、少なくとも私には、この「型のオブジェクト」charT
がオブジェクトに格納されたシーケンスの外にある可能性があることを意味しstd::string
ます。適合の実装例operator[]
:
reference operator[](size_type pos){
static contexpr charT default = charT();
if(pos == size())
return default;
return buf[pos];
}
現在、c_str()
/data()
は次のように指定されていますoperator[]
。
§21.4.7 [string.accessors]
const charT* c_str() const noexcept;
const charT* data() const noexcept;
戻り値: for each inの
p
ようなポインター。p + i == &operator[](i)
i
[0,size()]
これにより、上記のoperator[]
実装はp + size() != &operator[](size())
. ただし、ちょっとした工夫でこの問題を回避できます。
reference operator[](size_type pos){
static contexpr charT default = charT();
if(pos == size() && !evil_context) // assume 'volatile bool evil_context;'
return default;
return buf[pos];
}
struct evil_context_guard{
volatile bool& ctx;
evil_context_guard(volatile bool& b)
: ctx(b) {}
~evil_context_guard(){ b = false; }
};
const charT* c_str() const noexcept{
evil_context_guard g(evil_context = true);
// now, during the call to 'c_str()', the requirement above holds
// 'p + i == &operator[](i) for each i in [0,size()]'
const charT* p = &buf[0];
assert(p+size() == &operator[](size()));
return p;
}
さて、明らかな質問は...
上記のコードは本当に準拠していますか、それとも何か見落としていますか?