8

我同事的代码如下所示:

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

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

但我旁边的其他人说,过去曾讨论过这是否合法。谁能帮我解决这个问题?

4

3 回答 3

10

让我们把无效的可能性放在一边,*d因为这与问题的目标无关:std::string operator[]()在访问 index 处的“元素”时是否具有明确定义的行为std::string::size()

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()。否则,行为未定义。

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

在这种极端情况下,C++11 纠正了该版本的这种奇怪行为,该const行为与非 const 版本的行为如此不同。C++11 21.4.5“basic_string元素访问”说:

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

要求:pos <= size()

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

因此,对于 C++11 编译器,无论是否stringconst.

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

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

于 2012-05-13T09:46:19.117 回答
7

cppreference 是这样说的:

reference       operator[]( size_type pos );

const_reference operator[]( size_type pos ) const;

如果pos==size(),

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

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

于 2012-05-13T09:08:35.120 回答
0

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

  • 使用c_str().
  • 使用循环并在之后手动i < s.size()附加。\0

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

于 2012-05-13T09:09:45.737 回答