【发布时间】:2017-08-22 01:48:32
【问题描述】:
我有一个类 Foo,它有一些大类的向量。这个想法是,一个八进制树将由向量的元素递归构建,并且每个 OctreeNode 将有一个指向在 Foo 中找到的向量的几个元素的指针。 (在示例中,为简单起见,一个节点将仅指向向量的一个元素)
class Foo
{
vector<LargeClass> mLargeClasses;
void removeItem(const int index); //remove an element from the vector at the index
}
class OctreeNode
{
LargeClass* mLargeClass;
}
可以说,“为什么要在树构建后保留向量,并将对象存储在树本身中”。没错,我只想说,我还需要保持向量与构建的树平行。
虽然上述概念有效,但从基础向量中删除元素时我遇到了问题。在这种情况下,一些八叉树节点最终会出现悬空指针。
我的解决方案 #1: 如果调用 removeItem 函数,那么在它删除向量元素之前,它首先递归遍历八进制树,并使所有 mLargeClass 指针成为恰好指向该特定对象的 nullptr矢量元素。可以在节点中有 nullptr,因为我每次都检查 nullptr,当我访问它们时。
我的解决方案 #2: 让向量存储 shared_ptrs,让 OctreeNode 存储一个weak_ptr。我不喜欢这个,因为每次我访问树中的 weak_ptr 时,它都会在后台转换为 shared_ptr,所有原子计数器都会增加。我不是性能测试方面的专家,但我有一种感觉,它比带有 if 条件的简单指针访问要慢。
有人知道更好的解决方案吗?
我认为最优雅的是: 要拥有行为类似于 shared_pointer 的智能指针,计数,有多少其他指针引用它,记录它们,如果它被破坏,它会自动清空所有其他“观察者”指针指的是哪个?
【问题讨论】:
-
你需要使用
std::vector吗?你在迭代它吗?缓存局部性对您的应用程序有用吗?其他容器可能有更有利的失效规则。对std::shared_ptr的幼稚使用可能已经降低了缓存局部性。 -
从向量中的任何插入或删除都可能使 all 指向其元素的指针无效,因此解决方案 #1 不会真正起作用。
-
如果元素的顺序不重要,您可以通过将移除的元素与向量中的最后一个元素交换,然后弹出回退来实现解决方案#1。然后使用
nullptr更新所有指向已擦除元素的节点,并更新所有指向最后一个元素的节点,使其指向它在向量中的新位置。 -
@Avithohol 如果您依赖缓存位置,使用指针可能会毁掉它。
-
计算机科学中有两个难题。命名事物,缓存失效和关闭一个错误。您的 OctTreeNode 是一个缓存,并且您遇到了失效问题。考虑没有缓存。除非该缓存非常重要,否则只需再次找到您的节点可能会比使缓存失效工作所产生的开销更快。不管怎样,你的问题是这个缓存,为什么缓存对于如何缓存应该工作很重要。解释为什么。
标签: c++ c++11 pointers vector tree