我正在编写一个类(一个霍夫曼编码器,如果你很好奇),它需要包含一个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]
。 (但是,它再次起作用;这不是问题。)
我的问题是:
我对其他想法持开放态度,尽管我应该警告你我很保守。我想坚持使用&#34;基线&#34; C ++,即我会回避只有在C ++ 11或其他东西中的东西。而且我特别对sigc和boost这样的软件包的开销和复杂性持怀疑态度,所以我也不太可能想要使用他们的特殊容器或分配器。
答案 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字节。