std::string 是否需要将其字符存储在连续的内存中?

Does std::string need to store its character in a contiguous piece of memory?

提问人:sbi 提问时间:10/14/2015 最后编辑:NathanOliversbi 更新时间:5/15/2017 访问量:5203

问:

我知道在 C++98 中,既不需要也不需要使用连续存储。一旦有人指出这一点,就被视为一种疏忽,如果我没记错的话,C++03 修复了它。std::basic_string<>std::vector<>std::vector<>

似乎记得当 C++11 还被称为 C++0x 时,我读过关于需要使用连续存储的讨论,但当时我没有密切关注讨论,并且仍然仅限于 C++03 在工作中,所以我不确定它变成了什么。std::basic_string<>

那么是否需要使用连续存储呢?(如果是这样,那么哪个版本的标准首先需要它?std::basic_string<>

如果您想知道:如果您有代码将 &str[0] 的结果传递给需要写入连续内存块的函数,这一点很重要。(我知道str.data(),但由于显而易见的原因,旧代码不使用它。

C++ 语言律师 C++17

评论

0赞 Šimon Tóth 10/14/2015
好吧,由于需要恒定时间并且需要返回连续内存块,因此我得出的结论是。str.data()
1赞 slaphappy 10/14/2015
请参阅类似的问题 stackoverflow.com/questions/1986966/...stackoverflow.com/questions/2256160/...,它们回答了这个问题,但阅读起来并不容易。
1赞 sbi 10/14/2015
@Mr.kbok:我看过他们俩,读过答案,并认为我宁愿有一个最新的明确答案。
1赞 sbi 10/14/2015
@Angew:在 C++03 中,返回了 .str.data()const char*
1赞 Tony Delroy 10/14/2015
FWIW,我从未见过或听说过不连续的实现;任何对此感兴趣的人都可能会将其添加为独特的 STL 绳索。所以,在实践中,如果我是你,我只会偷看你的工作 C++03 的标准库(如果偏执狂),然后假设它总是连续的。std::basic_string

答:

29赞 Rahul Tripathi 10/14/2015 #1

C++11 标准,basic_string 21.4.1.5,

应将 basic_string 对象中的类似字符的对象存储起来 连续。也就是说,对于任何basic_string对象,恒等式 &*(s.begin() + n) == &*s.begin() + n 应为 n 的所有值成立 使得 0 <= n < s.size()。

2赞 101010 10/14/2015 #2

根据标准草案 N4527 21.4/3 类模板basic_string [basic.string]

basic_string是一个连续的容器(23.2.1)。

15赞 NathanOliver 10/14/2015 #3

在 c++03 中,不能保证字符串的元素是连续存储的。[基本字符串] 是

  1. 对于类似 char 的类型 charT,类模板basic_string描述可以存储 由任意数量的类字符对象组成的序列(第 21 条)。第一个元素 序列位于位置 0。如果给定的类字符类型是明确的,则这样的序列也称为“字符串” 从上下文。在本子句的其余部分,charT 表示这种给定的类 char 类型。字符串的存储 根据需要由类 basic_string 的成员函数通过 作为模板参数传递的 Allocator 类。分配器::value_type应与 图表。
  2. 类模板basic_string符合 (23.1.1) 中指定的 Sequence 的要求。 此外,由于 basic_string 支持的迭代器是随机访问迭代器 (24.1.5), basic_string符合 (23.1) 中规定的可逆容器的要求。 389 ISO/IEC 14882:2003(E)  ISO/IEC 21.3 类模板 basic_string 21 字符串库
  3. 在所有情况下,size() <= capacity()。

然后在 C++17 中,他们也改变了它

  1. 类模板basic_string描述可以存储由不同数字组成的序列的对象 序列的第一个元素位于零位置的任意字符状对象。这样的序列也是 称为“字符串”,如果它所包含的类字符对象的类型在上下文中是清楚的。在剩下的时间里 子句,basic_string对象中保存的类似 char 的对象的类型由 charT 指定。
  2. basic_string的成员函数使用作为模板参数传递的 Allocator 类的对象 为包含的类字符对象分配和释放存储空间233。
  3. basic_string是一个连续的容器(23.2.1)。
  4. 在所有情况下,size() <= capacity()。

强调我的

所以在 C++17 之前,它不能保证,但现在是。

由于施加了这种非保证的约束,因此几乎毫无意义,因为调用会为您提供字符串中字符的连续数组。因此,除非实现是按需且在恒定时间内执行此操作,否则字符串将是连续的。std::string::datastd::string::data


如果您想知道:如果您有代码将 &str[0] 的结果传递给需要写入连续内存块的函数,这一点很重要。(我知道str.data(),但由于显而易见的原因,旧代码不使用它。

的行为也发生了变化。在 C++03 中,我们有operator[]

返回:如果 pos < size(),则返回 data()[pos]。否则,如果 pos == size(),则 const version 返回 charT()。否则,行为是未定义的。

因此,如果您尝试 when 为空,则只能保证版本具有定义的行为。在 C++11 中,他们将其更改为:const&s[0]s

返回:*(begin() + pos) if pos < size()。否则,返回对 type 对象的引用 值为 charT() 的 charT,其中修改对象会导致未定义的行为。

因此,现在如果您尝试 when 为空,则版本和非版本都定义了行为。constconst&s[0]s

评论

3赞 Šimon Tóth 10/14/2015
即使在 C++03 中,也没有办法使用返回连续序列的常量时间函数,而实际存储是连续的。string::data()
0赞 NathanOliver 10/14/2015
@Let_Me_Be 是的,但如果标准没有强加要求,那么你就不能确定这种情况会在 100% 的时间内发生。我正在设想一个类似 deque 的结构。
0赞 Šimon Tóth 10/14/2015
该标准要求包含与字符串内容相同的内容,并对 施加了恒定时间要求。没有办法有一个类似 deque 的结构并保持恒定的时间限制。string::data()string::data()
0赞 NathanOliver 10/14/2015
@Let_Me_Be我在答案中添加了警告。string::data()
0赞 Nigel Heffernan 10/14/2015
感谢您扩展拉胡尔的回答。作为 C++ 的偶尔访问者,我必须解决流行的概括:其中之一是基于指针的语言不能保证任何非平凡的数据结构的物理布局:您所知道的只是结构中的数据可以从其指针透明地访问。透明地,而不是“通过对地址执行算术来按顺序”。因此,早期的“符合...一个可逆的容器“而不是”连续的“——你可以肯定,假设一个连续的块已经咬过一个人一次。