std::string 实现是否符合其中 's.c_str() + s.size()' 不一定与 '&s[s.size()]' 相同?

Is a std::string implementation conformant where 's.c_str() + s.size()' is not necessarily the same as '&s[s.size()]'?

本文关键字:size 不一定 相同 实现 string 是否 std str      更新时间:2023-10-16

§21.4.5 [string.access]

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

如果为pos < size(),则返回:*(begin() + pos)。否则,返回对类型为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;
}

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

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

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

  • 不幸的是,答案似乎是";是";,以及
  • 这当然不是标准的意图

因此,它似乎是一个缺陷

检查已知库缺陷的列表显然这个问题还没有报告。

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

我看不出它是如何一致的。用户代码永远无法遵守承诺的返回值。代码中的assert具有误导性,因为它位于错误的位置:函数尚未返回返回:要求适用于从函数返回的值,而不是其实现中的某个值(应该很清楚为什么这是一个荒谬的想法)。

断言应该在这里:

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

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