【问题标题】:Understanding the efficiency of an std::string了解 std::string 的效率
【发布时间】:2011-08-11 15:38:43
【问题描述】:

我正在尝试更多地了解 C++ 字符串。

考虑

const char* cstring = "hello";
std::string string(cstring);

std::string string("hello");

我是否正确假设两者都在应用程序的 .data 部分存储“hello”,然后将字节复制到堆上的另一个区域,由 std::string 管理的指针可以访问它们?

我怎样才能有效地存储一个非常长的字符串?我有点想从套接字流中读取数据的应用程序。我害怕连接很多次。我可以想象使用一个链表并遍历这个链表。

字符串已经吓到我太久了!

任何链接、提示、解释、更多细节都会非常有帮助。

【问题讨论】:

  • 真正的长是多少? 10MB? 20也许?还是您的意思是 10 GB 之类的东西?如今,计算机拥有千兆字节的 RAM。
  • 我想的更像是 10-100 MB。不过,这本来是一个开放式问题,所以请随意解释 =)。我很确定由于操作系统内存管理,您无法分配 10GB 的连续内存。我认为这样的大小需要一个列表。
  • @kispit - 在我的 64 位机器上,我可以分配内存,直到交换文件填满硬盘。几十GB没问题!
  • @kisplit - 此外,您假设“Hello”将存储在堆上对于许多实现来说是不正确的。小字符串存储在字符串对象中。见这里http://stackoverflow.com/questions/3770781/why-is-sizeofstring-32
  • @kisplit - 关于虚拟内存,我的观点是,分配大块内存仅在 32 位系统上存在问题,而不是在拥有数 TB 连续虚拟内存的 64 位地址空间上。

标签: c++ string performance construction


【解决方案1】:

我已将字符串存储在 10 或 100 的 MB 范围内,没有问题。自然,它将主要受到可用(连续)内存/地址空间的限制。

如果您要追加/连接,有几件事可能有助于提高效率:如果可能,尝试使用 reserve() 成员函数来预分配空间——即使您有一个粗略的知道最终大小可能有多大,它会随着字符串的增长而避免不必要的重新分配。

此外,许多字符串实现使用“指数增长”,这意味着它们会增长一些百分比,而不是固定的字节大小。例如,只要需要额外的空间,它就可以简单地将容量翻倍。通过以指数方式增加大小,执行大量连接变得更加有效。 (具体细节取决于您的 stl 版本。)

最后,另一种选择(如果你的库支持的话)是使用 rope 模板:绳索类似于字符串,除了在对非常大的字符串执行操作时效率更高。特别是,“绳子被分配在小块中,显着减少了大块引入​​的内存碎片问题”。 SGI's STL guide 的一些其他详细信息。

【讨论】:

    【解决方案2】:

    我认为效率不应该是问题。两者都会表现得足够好。

    这里的决定因素是封装。 std::string 是比 char * 更好的抽象。封装指针算术是好事。

    很多人想了很久,很难想出std::string。我认为出于毫无根据的效率原因而未能使用它是愚蠢的。坚持更好的抽象和封装。

    【讨论】:

    • 我不认为担心我们在这里讨论的数据大小的效率是不合理的; strcat 导致了一个有保证的 O(n^2) 解决方案,它可能会非常缓慢。 string.append 很有可能是 O(n),标准甚至可以保证它。
    • 不幸的是,很多人对 std::string 进行了长时间的思考并没有说明它的优势......它是 STL 中最受批评的部分之一,并且有充分的理由,我想。其他语言更适合字符串。
    • @kotlinski:我很想知道对 std::string 的一些批评。有链接吗?
    • @Eric:你可以找到网络......但基本上它归结为界面和性能。 1)很多基本的东西做起来很复杂。例如,修剪字符串,或将其设为大写/小写...为什么?如果你在其他语言中使用过字符串,你就会明白我的意思。 2) 在许多情况下性能不是很好 - std::string 的性能优于 C#/Java 字符串,而且 stringstreams 也比 sprintf 慢很多(如果你想连接浮点数或整数)。 3) 成员函数太多 - std::string 类真的很大,没有充分的理由。其中许多可能是免费功能。
    【解决方案3】:

    你可能知道,an std::string is really just another name for basic_string<char>.

    也就是说,它们是一个序列容器,内存将按顺序分配。如果您尝试使 std::string 大于您可以分配的可用连续内存,则可能会从 std::string 中获取异常。由于内存碎片,此阈值通常远低于可用内存总量。

    在尝试为图像分配大型连续 3D 缓冲区时,我遇到了分配连续内存的问题。但是这些问题至少不会在 100MB 左右开始发生,至少根据我的经验,在 Windows XP Pro 上(例如)。

    你的琴弦有这么大吗?

    【讨论】:

      【解决方案4】:

      由于您是从套接字读取字符串,因此您可以重用相同的数据包缓冲区并将它们链接在一起以表示巨大的字符串。这将避免任何不必要的复制,并且可能是最有效的解决方案。我似乎记得ACE 库提供了这样的机制。我会努力找到的。

      编辑: ACE 有 ACE_Message_Block 允许您以链表方式存储大消息。您几乎需要阅读 C++ 网络编程书籍才能理解这个庞大的库。 ACE 网站上的免费教程真的很烂。

      我敢打赌Boost.Asio 必须能够做与 ACE 的消息块相同的事情。 Boost.Asio 现在似乎比 ACE 拥有更大的份额,所以我建议先在 Boost.Asio 中寻找解决方案。如果有人能启发我们有关 Boost.Asio 解决方案的信息,那就太好了!


      是时候尝试使用 Boost.Asio 编写一个简单的客户端-服务器应用程序,看看有什么大惊小怪的。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-08-19
        • 2015-04-29
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多