§21.4.5 [string.access]
Является реализатором реализации std :: string, где 's.c_str() + s.size()' не обязательно совпадает с '& s [s.size()]'?
const_reference operator[](size_type pos) const;
reference operator[](size_type pos);
Возвращает:
*(begin() + pos)
еслиpos < size()
. В противном случае возвращает ссылку на объект типаcharT
со значениемcharT()
, где изменение объекта приводит к неопределенному поведению.
Вторая часть предполагает, мне по крайней мере, что этот «объект типа 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;
Возвраты: указатель
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;
}
Теперь, очевидный вопрос ...
ли выше код действительно совместимый или я что-то упускать из вида?
Одна вещь, которую я замечаю, заключается в том, что если вы на самом деле писали выписку для строкового объекта 'str':' char * p = str.c_str(); size_t i = str.size(); assert (p + i == & str [i]); 'утверждение не сработает с вашим кодом. Стандарт, похоже, не указывает конкретный контекст, в котором должен храниться инвариант, поэтому я должен быть осторожным, полагая, что он должен только удерживаться перед возвратом 'c_str()'. – pmdj