用于区域/竞技场分配的STL容器

时间:2015-07-02 16:19:38

标签: c++ pointers memory-management stl heap

我正在编写一个类(一个霍夫曼编码器,如果你很好奇),它需要包含一个STL容器不适合的专用二叉树。使用一些左/右指针定义TreeNode结构并构建该东西也没问题。我的问题涉及节点本身的分配。

我认为如果我使用STL容器作为我的" allocator"而不是直接为每个节点调用new,那将是非常好的。这很有吸引力,因为它会使破坏变得微不足道:我不必将我的树在析构函数中单独delete所有节点; STL容器的库存析构函数我用作我的"分配器"会自动完成。

我第一次选择&#34;分配器&#34;是std::vector<TreeNode>。但这根本不起作用,因为当然随着向量的增长,它必须重新分配自己并使我的所有指针无效。 所以我现在所做的就是坚持std::vector的想法,放弃指针;我以前每个地方都有一个指针,我有一个整数,将一个索引保存到我的向量中。 也就是说,在我的父类中,我有像

这样的成员
std::vector<TreeNode> _heap;        // all nodes in tree
int _root;                          // index into _heap

然后分配一个新节点我做这样的事情:

TreeNode newnode(/*whatever*/);
nodei = _heap.size();
_heap.push_back(newnode);
// now do something with nodei

事实上,这一切都很好,除了:使用索引而不是指针是一个简单的麻烦。我通常会将指向的节点引用为*nodep我必须使用_heap[nodei]。 (但是,它再次起作用;这不是问题。)

我的问题是:

  1. 是否存在一个STL容器类,保证其元素不会在以后移动,这样指向它们的指针在容器的生命周期内仍然有效?
  2. 指向STL容器中元素的指针是个好主意吗?
  3. 使用迭代器或引用代替指针来处理这种事情(也就是说,指向容器化堆中的元素)会不会更好?
  4. 有没有更好的方法来实现本地堆分配器,具有简单(即隐式)破坏语义?
  5. 我对其他想法持开放态度,尽管我应该警告你我很保守。我想坚持使用&#34;基线&#34; C ++,即我会回避只有在C ++ 11或其他东西中的东西。而且我特别对sigc和boost这样的软件包的开销和复杂性持怀疑态度,所以我也不太可能想要使用他们的特殊容器或分配器。

1 个答案:

答案 0 :(得分:1)

  

是否存在一个STL容器类,保证其元素不会在以后移动,这样指向它们的指针在容器的生命周期内仍然有效?

如果只有std::deque / push_back个元素,那么

emplace_back就不会移动元素,这对您的任务来说已经足够了,而且您可以指向元素。

此外,std::deque的大多数流行实现都以块的形式分配内存,其中一个块可以按顺序存储多个元素 - 这样可以改善局部性,并减少分配计数(与std::list相比)。

  

指向STL容器中元素的指针是不是一个好主意?

只要您了解基础语义和保证(您可以在C ++ ISO中阅读),这是个好主意。

例如,如果你不改变std::vector的容量并且不调整它的大小 - 指向vector中元素的指针就可以了。

  

使用迭代器或引用代替指针来处理这种事情(也就是说,指向容器化堆中的元素)会更好吗?

我没有看到任何好处,除了一些STL实现可能会在Debug版本中提供额外的防御性检查。

  

有没有更好的方法来实现本地堆分配器,具有简单(即隐式)破坏语义?

实际上我喜欢他们想要使用索引,即你region[node_index](尽管在代码期望&#34; true&#34;指针的情况下并不总是可以接受)。我认为这种方法有几个潜在的好处:

  • std::vector呈指数级增长,导致O(log N)元素的N分配。有可能为指针获得类似的属性,但它更复杂 - 你应该维护不同大小的块列表,比如std::vector<std::vector<Node>>,其中每个新块的容量为total_size * k,你应该确定不改变它(因为指向元素的指针)。

  • 您可以控制sizeof(index) - 您可以使用适合您任务的索引类型,例如它可能是1-2个字节。但指针的大小可能会大得多,特别是在x64上 - 大小为8字节。