讨论
-
众所周知,从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
的内部存储缓冲区,而不是以空字符结尾的副本。
问题:
- 标准中是否明确规定
std::basic_string
内部存储缓冲区必须以空字符结尾 - 如果没有明确的声明(即,问题#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结尾。