以Null结尾的字符串,它真的是由标准规定的吗

Null terminated string, is it really dictated by the standard?

本文关键字:标准规 真的 Null 结尾 字符串      更新时间:2023-10-16

讨论

  • 众所周知,从C++11及以后的std::basic_string s被认为具有空字符终止的内部存储缓冲区。

  • 这一变化的主要原因之一是,std::basic_string的先前定义只允许非常有限的字符串并发访问,从而限制了多线程应用程序的性能。(关于std::basic_string变化的更多原因,可以在建议N2534中阅读(。

  • 然而,在阅读标准时,我找不到明确指出std::basic_string必须具有以null字符结尾的内部存储缓冲区的引用。

  • 我发现的唯一隐含的引用是§21.4.7.1/1&3个basic_string访问者[string.accessors]:

const charT* c_str() const noexcept;

const charT* data() const noexcept;

1返回:一个指针p,使p + i == &operator[](i)代表[0,size()]中的每个i 3要求:程序不得更改存储在字符数组中的任何值

  • 我认为,由于效率的原因,并且由于§21.4.7.1/3要求程序不得更改返回的缓冲区,因此std::basic_string::c_str()std::basic_string::data()中的大多数实现程序都返回了以空字符结尾的内部缓冲区。

  • 然而,该标准并没有规定std::basic_string::c_str()std::basic_string::data()必须返回的缓冲区必须是std::basic_string的内部存储缓冲区,而不是以空字符结尾的副本。

问题:

  1. 标准中是否明确规定std::basic_string内部存储缓冲区必须以空字符结尾
  2. 如果没有明确的声明(即,问题#1的简短回答是否(,这是否意味着实现者可以在没有以null字符结尾的内部存储缓冲区的情况下实现std::basic_string,因此,由于C++11字符串以null结尾的广泛概念是错误的

来自21.45

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

1需要:pos <= size()

2退货:如果是pos < size(),则为*(begin() + pos),否则为对具有值CCD_ 27的类型为CCD_;参考值应不可修改。

请注意,s[s.size()]定义良好,需要返回NUL字符。

然而,这本身并不需要NUL指定的内部存储21.4.1/5可以这样说:

basic_string对象中的类字符对象应连续存储。也就是说,对于任何basic_string对象s,标识&*(s.begin() + n) == &*s.begin() + n应适用于n的所有值,使得0 <= n < s.size()

请注意,只有在n < s.size()之前才需要连续存储,但s.size()本身不需要连续存储。因此char* p = &s[0];不一定指向NUL端接的缓冲区,因为标准不要求p[s.size()]有效。

实际上,在data()c_str()operator[]的需求之间,任何正常的实现都将维护一个NUL端接的存储。但标准似乎并没有排除疯狂的实现。

在C++11中,c_str()data()都需要返回一个指向内部存储的指针(对不起,我没有直接的引号来支持这一点(。在早期版本中,c_str()不需要这样做,但data()需要这样做。实现器可以(但很少(实现写时复制语义,这样c_str()返回的指针就不是原始的内部存储。

在所有版本中,c_str()都需要返回一个以null结尾的指针。因此,这意味着在C++11中,内部存储必须以null结尾。