【发布时间】:2012-08-02 08:03:58
【问题描述】:
§21.4.5 [string.access]
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)对应[0,size()]中的每个i。
这将使上述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()返回之前保持。
标签: c++ string c++11 language-lawyer