【发布时间】:2020-05-07 23:59:17
【问题描述】:
我相信对此的常见反应是“否”,因为容器的 end() 迭代器代表了一个“过去的”地址,它是取消引用的未定义行为。我在标准中找不到明确的声明可以免除字符串不受此约束,即使字符串在其他容器上具有特殊情况。
C++11 标准声明您可以读取字符串末尾的一个索引。 string[size()] 引用空终止符的只读值。
24.3.2.5 basic_string 元素访问[string.access]
const_reference operator[](size_type pos) const;
reference operator[](size_type pos);(1) 需要:
pos <= size()。(2) 返回:
*(begin() + pos) if pos < size()。否则,返回对类型对象的引用charT的值为charT(),其中将对象修改为charT()以外的任何值会导致 未定义的行为。
front() 被定义为等同于return operator[](0),对于空字符串,它等同于return operator[](size())。
end() - begin() 被明确定义为字符串长度的差异,因此end() 必须指向size() 的索引,以便合理实现来定义该算术。
在上面的标准摘录中,它声明operator[](pos) 等价于*(begin() + pos) 如果pos < size()。它确实没有说您可以取消引用begin() + size(),但您认为假设这应该被明确定义是否合理?或者更好的是,您是否知道一些使字符串迭代器不受约束的证明?
另外,是否可以证明任何i 的*(begin() + i) 等价于operator[](i)?
【问题讨论】:
-
取消引用 any 容器的
end()迭代器是不合法的,包括std::string。从逻辑上讲,end()可以引用字符串的空终止符,C++11 要求它存在于内存中。但是end()不需要引用内存中的 actual 空终止符。唯一的要求是operator[](size())引用“一个charT类型的对象”,它可以很容易地定义在string对象之外的静态char(0),这很重要对于为空字符串存储nullptrchar*指针的实现。这不会改变end()的行为方式。 -
@RemyLebeau 因此我对“理智”实现的注释。如果
end()指向远离字符串内存的静态值,则实现将需要在整个地方检查这种情况,以处理简单的事情,例如end() - 1,它应该指向字符串中的最后一个字符。我知道这对于任何容器通常都是非法的,但也许应该对字符串进行纠正?问题是是否已经有我找不到的证据。 -
我希望“理智”的实现使
end()指向空终止符的地址,以保持简单。即使支持它的内存是有效的,这仍然不能使end()合法地取消引用。使std::string::end()迭代器成为一种特殊情况,其行为与其他容器不同,只会使设计用于任何容器的算法复杂化。没有充分的理由永远取消引用std::string::end()迭代器。所以我认为标准中没有什么可以“纠正”的。 -
@RemyLebeau
operator[](size())已经是字符串容器的特例,对于其他容器是非法的。string有一个特殊情况,你可以读完一个;为什么纠正标准以使end()行为相同没有意义? -
@RemyLebeau Until C++11,
std::stringwas not required to include a trailing nul until you calledc_str()。例如,Facebook 也实现了自己的std::string,没有空终止符:The strange details of std::string at Facebook
标签: c++ string language-lawyer std