【问题标题】:Resizable char buffer container type for C++C++ 的可调整大小的字符缓冲区容器类型
【发布时间】:2011-08-23 05:57:46
【问题描述】:

我正在使用带有 C++ 的 libcurl(HTTP 传输库)并尝试从远程 HTTP 服务器下载文件。下载文件时,我的回调函数会被调用多次(例如每 10 kb)向我发送缓冲区数据。

基本上我需要“字符串缓冲区”之类的东西,这是一种将char 缓冲区附加到现有字符串的数据结构。在 C 中,我分配 (malloc) 一个 char*,然后随着新缓冲区的到来,我 realloc 然后 memcpy 以便我可以轻松地将缓冲区复制到调整大小的数组。

在 C 中,有多种解决方案可以实现这一点。

  1. 我可以继续使用mallocreallocmemcpy,但我很确定在 C++ 中不推荐使用它们。
  2. 我可以使用vector<char>
  3. 我可以使用stringstream

我的用例是,我将一次附加数千个项目 (chars),在所有项目完成后(下载完成),我将一次性阅读所有项目。但我将来可能需要seek 之类的选项(在数组解决方案(1)中很容易实现),但现在它的优先级很低。

我应该使用什么?

【问题讨论】:

    标签: c++ data-structures stl


    【解决方案1】:

    我会选择stringstream。只需在接收数据时插入其中,完成后即可从中提取完整的std::string。我不明白您为什么要将seek 放入数组中?无论如何,如果你知道块的大小,你就可以计算出相应的块在字符串中的位置。

    【讨论】:

    • 我正在实现一个 FUSE(文件系统)包装器,如果文件系统将有 fseek 调用,我需要以某种方式实现它。我可以动态分配stringstream 而不是在堆栈中吗?
    • 你可以动态分配任何东西。但是在内部无论如何都会动态分配一个字符串流,所以我认为你不需要这样做。您可以像在任何流上搜索一样在字符串流上搜索。
    • 它是否比vector<char> 解决方案有更多的附加时间或内存开销?它的优点是什么?搜索只是低优先级。
    • 如果你只需要seek到一个特定的字符,stringstream提供seekg。或者只是提取字符串并使用[] 索引。如果你的意思是如果可以做到new stringstream,那么是的,当然可以。内部缓冲区如何分配的细节可能无法保证,而且您似乎无法提供自己的分配器。 编辑:哇,我打字慢……
    • @ahmet,在字符串流中使用 0x00 没有任何限制。
    【解决方案2】:

    我不确定是否有很多人会同意这一点,但对于那个用例,我实际上会使用一个链表,每个节点都包含一个使用new 分配的任意大的字符数组。我的理由是:

    • 项目一次以大块的形式添加,在后面一次一个。
    • 我认为这可能会占用大量空间,因此当向量需要更多空间时,您可以避免重新分配事件。
    • 由于项目是按顺序读取的,因此单向链接列表的损失不会影响您。

    如果在列表中查找成为优先事项,但这不会起作用。如果最终不是很多数据,我真的认为向量会很好,尽管它不是 最有效的结构。

    【讨论】:

    • +1 确实是个好主意,但完整的阅读和搜索可能需要大量的实现和测试,stringstream 解决方案可以进行更多的重新分配,但它很健壮并且通常是安全的。我想我会在这个权衡中选择stringstream。谢谢你的想法。
    【解决方案3】:

    如果你只需要追加字符缓冲区,你也可以简单地使用std::string和成员函数append。最重要的是,stringstream 为您提供格式、功能,因此您可以添加数字、填充等,但从您的描述来看,您似乎不需要。

    【讨论】:

      【解决方案4】:

      我会使用vector<char>。但即使有搜索,它们都可以工作,所以你的问题确实是一种风格,没有明确的答案。

      【讨论】:

        【解决方案5】:

        我想我会使用deque<char>。与vector 相同的接口,vector 可以,但每次追加超出其现有容量时,vector 需要复制整个数据。增长是指数级的,但您仍然期望log N 重新分配,其中N 是您附加的相同大小的数据块的数量。 Deque 不会重新分配,因此在向量需要多次重新分配的情况下,它是首选容器。

        假设回调被传递给char* 缓冲区和长度,那么复制和附加数据的代码就足够简单了:

        mydeque.insert(mydeque.end(), buf, buf + len);
        

        如果你想要,最后得到一个字符串:

        std::string mystring(mydeque.begin(), mydeque.end());
        

        我不太清楚seek 是什么意思,但显然deque 可以通过索引或迭代器访问,与vector 相同。

        但是,另一种可能性是,如果您希望在下载开始时有一个内容长度,您可以在开始之前使用vectorreserve() 为数据提供足够的空间,从而避免重新分配。这取决于您发出的 HTTP 请求以及发送给哪些服务器,因为某些 HTTP 响应将使用分块编码并且不会预先提供大小。

        【讨论】:

          【解决方案6】:

          创建您自己的Buffer 类以抽象出存储的详细信息。如果我是你,我可能会根据 std::vector<char> 实现缓冲区。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2023-04-05
            • 1970-01-01
            • 2010-10-21
            • 1970-01-01
            • 2012-03-16
            • 1970-01-01
            • 2019-04-09
            • 2020-05-15
            相关资源
            最近更新 更多