C++03和C++11中c_str函数规范的差异

26
在C++中,std::string中的c_str()函数的参考文献中提到:

返回值
指向底层字符存储的指针。
data()[i] == operator[](i) 对于[0,size())内的每个i成立 (C++11之前)。
data() + i == &operator[](i) 对于[0,size()]内的每个i成立(自C++11起)。

我不理解两者之间的区别,除了自C++11以来范围增加了一个元素。

难道前面的语句data()[i] == operator[](i)对后者也是成立的吗?


9
之前的措辞允许写时复制实现,这可能需要为 c_str() 进行复制。 - sp2danny
我会说 data()[size()] 是未定义行为。 - Jarod42
1
@Jarod42 在C++11实现中不是这样的。 - Chiel
3个回答

20

除了自 C++11 起的区间增量增加了一个元素以外,以下两者仍有很大的差别:

data()[i] == operator[](i)

并且:

data() + i == &operator[](i)

主要区别在于原型中的 & 运算符。

旧的原型允许在写操作发生时进行 复制,因为返回的指针可以指向持有原始字符串的另一个缓冲区。

data()[i]data() + i 之间的另一个区别不是关键性的,因为它们是等效的


C++ 和 C++11 之间的差别在于,在前者中,标准并没有明确规定 std::string 是否会具有空终止符。然而在后者中,这一点已经被指定。

换句话说:在C++11中,std::string是否总是以空字符结尾? 是的。


1
可以说,一种实现方式是为终止符保留空间,并从c_str()中惰性地将其置为空。当然,这不是一个合理的做法。 - Sneftel
不,这是一个几乎痛苦地迂腐的观点。只是说说而已。 :) - Sneftel

9
请注意括号的不同之处:

[0,size())

[0,size()]

第一个括号表示“排除范围”(即在索引为size的位置上的项不包括在内),而第二个括号表示“包含范围”(即在索引为size的位置上的项也包括在内)。 在C++之前,这种情况下没有处理终止符的存在,但是在C++11中,访问位于size()位置的字符已经是定义良好的行为。
至于data()[i] == operator[](i)data() + i == &operator[](i)之间的区别,后者对潜在实现施加了更多限制。在第一种情况下,由data()返回的指向缓冲区的指针可能与由operator[]返回其引用值存储的缓冲区的指针不同。当复制字符串的非const限定操作符[]调用后创建新缓冲区时,就可能出现这种情况。

0
在C++11之前,字符串数据是否以空字符结尾是未指定的。C++11规定必须以空字符结尾。

但是为什么data()[i]data()+i之间有符号差异呢? - Chiel
我认为VTT已经解释过了 - 这是半开和开区间之间的差异。 - user2100815
我不明白。data()[i] 不就等同于 *(data() + i) 吗? - Chiel
但是c_str已经存在并且必须在常数时间内运行,这是否意味着空终止符存在? - Nir Friedman
@Nir 我所知道的所有实现都提供了它,但是C++98标准没有规定必须有一个。 - user2100815

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接