字符串[长度()]C++,可以吗

string[length()] in C++, is it OK?

本文关键字:C++ 长度 字符串      更新时间:2023-10-16

我同事的代码看起来像这样:

void copy(std::string const& s, char *d) {
  for(int i = 0; i <= s.size(); i++, d++)
    *d = s[i];
}

他的应用程序崩溃了,我认为这是因为这超出了范围s访问,因为条件应该最多 s.size() - 1 .

但是我旁边的其他人说,过去曾讨论过这是合法的。谁能为我澄清一下?

让我们抛开*d无效的可能性,因为这与问题似乎针对的问题无关:在索引std::string::size()访问"元素"时,std::string operator[]()是否具有明确定义的行为。

C++03标准对string::operator[]()(21.3.4"basic_string元素访问"(有以下描述:

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

返回:如果pos < size(),则返回data()[pos]。否则,如果pos == size() ,则 const 版本返回 charT() 。 否则,行为是未定义的。

由于示例代码中的sconst,因此行为是明确定义的,s[s.size()]将返回一个空字符。 但是,如果s不是const string,则行为将是不确定的。

C++11 纠正了 const 版本的这种奇怪行为,在此边缘情况下,该行为的行为与非常量版本的行为大不相同。 C++11 21.4.5 "basic_string元素访问"说:

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

要求:pos <= size()

返回:*(begin() + pos ( 如果pos < size(),否则引用 到值为 charT() 的 T 类型的对象;引用的值 不得修改。

因此,对于 C++11 编译器,无论string是否const,行为都是明确定义的。

与这个问题无关,我觉得 C++11 说"引用的值不得修改"有点奇怪——我不清楚该条款是否仅适用于pos == size()的情况。 我很确定有大量现有的代码可以执行诸如s[i] = some_character;之类的事情,其中s是非常量std:stringi < s.size()。 现在这是未定义的行为吗?我怀疑该条款仅适用于特殊情况charT()对象。

另一个有趣的事情是,这两个标准似乎都没有要求返回s[s.size()]对象的地址与返回s[s.size() - 1]对象的地址有任何关系。 换句话说,返回的charT()引用似乎不必与字符串数据的末尾相邻。 我怀疑这是为了让实现者选择在需要时只返回对该哨兵元素的单个静态副本的引用(这也解释了 C++11 的"不得修改"限制,假设它仅适用于特殊情况(。

cppreference 是这样说的:

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

如果pos==size()

  • const 版本返回对值为 CharT(((空字符(的字符的引用。(至C++11(
  • 两个版本都返回对值为 CharT(((空字符(的字符的引用。通过非常量引用修改空字符会导致未定义的行为。(自C++11起(

所以只要你不修改空字符就可以了。

如果你想这样做(你的同事的代码也尝试复制终止(,你可以

  • 使用 c_str() .
  • 将循环与i < s.size()一起使用,然后手动附加

编辑:
好吧,从其他答案来看,我现在更倾向于认为 Abyx 的评论是正确的:数组d可能溢出(或者甚至可能没有分配(。首先检查一下。
但请确保也复制