Reputation: 131799
§21.4.5 [string.access]
const_reference operator[](size_type pos) const;
reference operator[](size_type pos);
Returns:
*(begin() + pos)
ifpos < size()
. Otherwise, returns a reference to an object of typecharT
with valuecharT()
, where modifying the object leads to undefined behavior.
The second part implies, to me atleast, that this "object of type charT
" may reside outside of the sequence stored in the std::string
object. Example implementation of a conforming operator[]
:
reference operator[](size_type pos){
static contexpr charT default = charT();
if(pos == size())
return default;
return buf[pos];
}
Now, c_str()
/data()
, are specified in terms of operator[]
:
§21.4.7 [string.accessors]
const charT* c_str() const noexcept;
const charT* data() const noexcept;
Returns: A pointer
p
such thatp + i == &operator[](i)
for eachi
in[0,size()]
.
This would make the above operator[]
implementation non-conformant, as p + size() != &operator[](size())
. However, with a bit of trickery, you can circumvent this problem:
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;
}
Now, the obvious question is...
Is the above code really conformant or did I overlook something?
Upvotes: 10
Views: 364
Reputation: 234504
I don't see how it could be conformant. User code can never observe the promised returned value. The assert
in the code is misleading because it is in the wrong place: the function has not returned yet. Returns: requirements apply to be value returned from the function, not to some value within its implementation (it should be obvious why that is a nonsensical idea).
The assertion should be here:
auto p = s.c_str();
assert(p + s.size() == &operator[](s.size()));
I believe the wording that treats s[s.size()]
specially is simply meant to forbid you from blowing up the null terminator.
Upvotes: 0
Reputation: 145279
Ignoring the given code, considering only the question, I think that
Hence, it appears to be a defect.
Checking the list of known library defects apparently this issue has not yet been reported.
So, as I stated in chat, I recommend posting it to [comp.std.c++], in order to get resolved the question of whether it really is a defect, and if so, to get it into the defects list and fixed.
Upvotes: 4