【问题标题】:Does std::string need to store its character in a contiguous piece of memory?std::string 是否需要将其字符存储在连续的内存中?
【发布时间】:2016-01-12 11:47:31
【问题描述】:

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

似乎记得在 C++11 仍称为 C++0x 时,我曾阅读过要求 std::basic_string<> 使用连续存储的讨论,但我没有密切关注讨论然后,在工作中仍然受限于 C++03,所以我不确定它的结果如何。

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

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

【问题讨论】:

  • 好吧,既然str.data()需要是常数时间并且需要返回一个连续的内存块,我会得出结论是的。
  • 查看类似的问题 stackoverflow.com/questions/1986966/…stackoverflow.com/questions/2256160/…,它们回答了这个问题,但阅读起来并不简单。
  • @Mr.kbok:我看过他们两个,阅读了答案,并认为我宁愿有一个最新的明确答案。
  • @Angew:在 C++03 中,str.data() 返回了一个const char*
  • FWIW,我从未见过或听说过不连续的 std::basic_string 实现;对此感兴趣的任何人都可能会将其添加为独特的STL rope 相似。所以,在实践中,如果我是你,我只会偷看你的工作 C++03 的标准库(如果偏执的话),然后在假设它总是连续的情况下进行编码。

标签: c++ c++11 c++14 language-lawyer c++17


【解决方案1】:

C++11 standard,basic_string 21.4.1.5,

basic_string 对象中的 char-like 对象应被存储 连续地。也就是说,对于任何 basic_string 对象,身份 &*(s.begin() + n) == &*s.begin() + n 应适用于所有 n 值 这样 0

【讨论】:

    【解决方案2】:

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

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

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

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

    强调我的

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

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


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

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

    返回:如果 pos

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

    返回: *(begin() + pos) 如果 pos

    所以现在const 和非const 版本都已定义行为,如果您在s 为空时尝试&s[0]

    【讨论】:

    • 没有办法让string::data() 成为常​​数时间函数,它返回一个连续序列而实际存储不连续,即使在 C++03 中也是如此。
    • @Let_Me_Be 是的,但如果标准没有强加要求,那么您不能确定这会在 100% 的时间内发生。我正在设想一个类似双端队列的结构。
    • 标准要求string::data()包含与字符串内容相同的内容,并对string::data()提出恒定时间要求。没有办法拥有类似双端队列的结构并保持恒定的时间限制。
    • @Let_Me_Be 我在答案中添加了关于string::data() 的警告。
    • 感谢您扩展 Rahul 的回答。作为 C++ 的偶尔访问者,我必须解决流行的概括:其中之一是基于指针的语言不能保证任何非平凡数据结构的物理布局:你所知道的是结构中的数据将透明可从其指针访问。 透明地,而不是“按顺序对地址执行算术运算”。因此,早期的规范是“符合……可逆容器”而不是“连续的”——而且你可以肯定假设一个连续的块已经咬过某人一次。
    【解决方案3】:

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

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

    【讨论】:

      猜你喜欢
      • 2019-02-19
      • 2017-02-15
      • 2020-04-20
      • 2011-10-01
      • 1970-01-01
      • 2021-08-27
      • 2010-12-31
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多