【问题标题】:C++ "vector" with elements of variable size具有可变大小元素的 C++“向量”
【发布时间】:2013-06-19 08:51:17
【问题描述】:

对于一个非常具体的应用程序,我想使用一个容器,其中包含可变大小的元素并且在内存中是连续的。基本原理是访问将主要是顺序的,因此将所有数据放在同一个线性数据结构中应该有助于缓存行为。

当然随机访问是不可能的,但数据结构应该使用矢量样式的push_back 方法动态调整大小。

这样的容器存在吗?怎么称呼?

编辑以解决 Arne Mertz 的评论:

我要表示的结构是一个图形。容器将包含节点列表,每个节点都有边列表,可能表示为指向其他(先前)节点的指针列表。

struct Node {
  //various fixed size fields about the node itself
  ...

  unsigned short n_edges;
  Node * edges[n_edges]; // schematically
};

【问题讨论】:

  • @H2CO3 :我希望这些元素在内存中是连续的。我已经编辑了问题以使事情更清楚。
  • 然后std::vector。如果您想要连续的元素,那么这是一个具有O(1) 访问和O(n) 插入和删除的数组或向量。如果你想要O(1) 插入和删除,那么这是一个链接列表,然后它有O(n) 遍历,它在内存中不连续。你不能吃你的午餐吃你的午餐,决定你想要哪一个。
  • 具有可变元素的容器充其量很难实现。此外,您将很难对这些元素做任何事情,因为您不知道容器的第 N 个元素将具有什么类型。想到一件事 boost::variadic 或支持类类型成员的 C++11 联合。无论如何都将难以实施。如果您告诉我们更多关于您的数据类型的信息,我们可以为您提供有关可能实施的更多详细信息。
  • 这是评论,不是答案。好吧,也许评论太长了,好吧。
  • 过早优化?

标签: c++ boost data-structures stl containers


【解决方案1】:

Boost Intrusive singly linked list 呢。您需要自己实现自己的分配。您可以简单地分配一个大区域(char[] 类型)并在该区域内创建具有递增地址的对象(不要忘记对齐)。如果您的区域已满,您可以简单地再创建一个。但是您必须自己进行所有分配并管理对象生命周期。此外,您可以使用 std::vector 作为 O(1) 访问的支持结构。

【讨论】:

  • 这样可以,但是会浪费指向下一个元素的指针。
  • 我认为列表在与算法一起使用方面有其优势。例如,您可以迭代。 boost.org/doc/libs/1_53_0/doc/html/intrusive/… 解释了如何计算这些指针。
  • 经过反思,我认为这是最好的答案。在我的示例中,可以从指针中推断出边数,因此不会浪费任何东西。
【解决方案2】:

解决此问题的一种方法是使用内部 void 指针。然后,每个元素都存储在该内存中。每个元素都以它的大小开始。对容器进行迭代将使字节指针增加当前元素的大小。如果您想要随机访问,您可以使用包含指向所有元素的指针的目录。

【讨论】:

  • 是的,就是这个想法。我想知道这类事情是否已经众所周知,并且可能已经作为 boost 甚至标准库的一个不起眼的部分实现了。
  • 查看 Doom WAD 编辑器的源代码。 Doom WAD 在目录中具有对象(或块)大小,但您不希望这样,因为这样您就必须在迭代时对每个项目进行目录查找,由于 cahce 未命中的数量增加,这可能会显着变慢。跨度>
【解决方案3】:

您可以创建一个std::vector<char> v 和一个std::list<size_t> lv 将充当可增长的字符缓冲区,l 将包含对象的偏移量。

现在您需要编写自己的 push_back ,它将当前偏移量插入到 std::list 并在位置复制对象:&v[offset](记得事先增加 v)。

template <class T>
void push_back(T t)
{
    size_t vectorSize = v.size());
    size_t objectSize = sizeof(T);

    l.pushback(vectorSize);

    v.reserve(vectorSize + objectSize);
    st::memcpy(&v[vectorSize], &t, objectSize);
}

【讨论】:

    【解决方案4】:

    用一块动态内存实现一个类。 编写一个函数以在块的末尾推送一个可变长度的结构。 将块的偏移量放在一个向量中,以便您轻松迭代块, 和块的随机访问。

    当动态内存区域变满时,重新分配更大的内存并将旧的块数据复制到其中。

    冲洗重复。

    【讨论】:

    • 不。您必须为可变长度元素动态分配一块内存。在加载时,您将指针存储到向量中的新元素。
    • @EvilTeach :向量只会添加对我的数据结构的随机访问。这很好,但我问的是“内存块”的实现方式。
    猜你喜欢
    • 2017-08-03
    • 1970-01-01
    • 2020-04-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-24
    • 1970-01-01
    • 1970-01-01
    • 2013-03-09
    相关资源
    最近更新 更多