10

§21.4.5 [string.access]

const_reference operator[](size_type pos) const;
reference operator[](size_type pos);

返回: *(begin() + pos)如果pos < size()。否则,返回对charT具有 value类型的对象的引用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)对于每个iin [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;
}

现在,显而易见的问题是……

上面的代码真的符合还是我忽略了什么?

4

2 回答 2

4

忽略给定的代码,只考虑问题,我认为

  • 不幸的是,答案似乎是“是”,并且
  • 这当然不是标准的意图

因此,它似乎是一个缺陷

检查已知库缺陷列表显然尚未报告此问题。

因此,正如我在聊天中所说,我建议将其发布到 [comp.std.c++],以便解决它是否真的是缺陷的问题,如果是,将其放入缺陷列表并修复。

于 2012-08-04T15:47:21.633 回答
0

我不明白它怎么可能是一致的。用户代码永远无法观察到承诺的返回值。代码中的assert具有误导性,因为它位于错误的位置:函数尚未返回。返回:要求适用于从函数返回的值,而不是其实现中的某个值(应该很明显为什么这是一个荒谬的想法)。

断言应该在这里:

auto p = s.c_str();
assert(p + s.size() == &operator[](s.size()));

我相信s[s.size()]特殊对待的措辞只是为了禁止你炸毁空终止符。

于 2012-08-05T17:28:01.977 回答