string :: c_str()在C ++ 11中不再以null结尾吗?

时间:2011-09-26 10:56:52

标签: c++ string c++11

在C ++ 11中,basic_string::c_str被定义为与basic_string::data完全相同,后者被定义为与*(begin() + n)*(&*begin() + n)完全相同(当0 <= n < size())。

我找不到任何要求字符串在其末尾始终具有空字符的内容。

这是否意味着c_str()不再保证产生以空字符结尾的字符串?

4 个答案:

答案 0 :(得分:80)

现在需要字符串在内部使用以null结尾的缓冲区。看看operator[](21.4.5)的定义:

  

需要: pos <= size()

     

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

回顾c_str(21.4.7.1/1),我们发现它是根据operator[]定义的:

  

返回:指针pp + i == &operator[](i)中的每个i [0,size()]

c_strdata都需要为O(1),因此实现强制使用以null结尾的缓冲区。

此外,正如David Rodríguez - dribeas在评论中指出的那样,返回值要求也意味着您可以使用&operator[](0)作为c_str()的同义词,因此终止空字符必须位于相同的缓冲区(因为*(p + size())必须等于charT());这也意味着即使终结符被懒惰地初始化,也不可能在中间状态下观察缓冲区。

答案 1 :(得分:23)

实际上,新标准确实规定.data()和.c_str()现在是同义词。但是,它并没有说.c_str()不再是零终止的:)

这只意味着您现在可以依赖.data()也可以使用零终止。

  

论文N2668将std :: basic_string的c_str()和data()成员定义为    如下:

 const charT* c_str() const; 
 const charT* data() const; 
     

返回:指向长度数组的初始元素的指针    size()+ 1,其第一个size()元素等于对应的    字符串的元素由* this控制,其最后一个元素是a    charT()指定的null字符。

     

要求:程序不得更改存储的任何值    字符数组。

请注意,这样做 NOT 意味着任何有效的std :: string都可以被视为C字符串,因为std :: string可以包含嵌入的空值,这会在以后过早地结束C字符串直接用作const char *。

附录:

我无法访问实际发布的final spec of C++11,但似乎确实在规范的修订历史中某处删除了措辞:例如http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3242.pdf

  

§21.4.7basic_string字符串操作[string.ops]

     

§21.4.7.1basic_string访问者[string.accessors]

     const charT* c_str() const noexcept;
     const charT* data() const noexcept;
     
      
  1. 返回:指针p,p + i == &operator[](i)中每个i的{​​{1}}。
  2.   
  3. 复杂性:恒定时间。
  4.   
  5. 要求:程序不得更改存储在字符数组中的任何值。
  6.   

答案 2 :(得分:10)

“历史”是很久以前当每个人都在单线程中工作,或者至少线程是拥有自己数据的工作者时,他们为C ++设计了一个字符串类,使得字符串处理比以前更容易,并且他们重​​载了operator +来连接字符串。

问题是用户会做类似的事情:

s = s1 + s2 + s3 + s4;

并且每个连接都会创建一个必须实现字符串的临时连接。

因此,某人有了“懒惰评价”的脑波,这样你就可以在内部存储所有字符串的某种“绳子”,直到有人想把它作为C字符串读出来,此时你要将内部表示改为一个连续的缓冲区。

这解决了上面的问题但引起了其他令人头疼的问题,特别是在多线程世界中,人们期望.c_str()操作是只读的/不会改变任何东西,因此不需要锁定任何东西。在类实现中过早内部锁定以防万一有人在多线程中执行它(当时甚至没有线程标准)也不是一个好主意。事实上,除了每次复制缓冲区之外,做任何事情都要花费更多。与字符串实现相同的原因是“写入时复制”实现。

因此,使.c_str()成为一个真正不可变的操作是最明智的做法,但是可以在一个现在是线程感知的标准中“依赖”它吗?因此,新标准决定明确说明你可以,因此内部表示需要保持空终止符。

答案 3 :(得分:2)

很好看。这肯定是最近采用的标准的缺陷;我确信没有意图打破目前使用c_str的所有代码。我会建议一个缺陷报告,或至少在comp.std.c++中提出问题(如果涉及缺陷,通常会在委员会面前结束)。