在类Block
的构造函数中,我将创建的实例推送到静态向量static std::vector<Block*> allBlocks
,并在析构函数中删除它们。
如果我只是创建没有指针的块,即。 Block b;
但是,希望让另一个类返回std::vector<Block*> grid
以供使用,它会创建它们并将它们也添加到allBlocks
向量中。销毁grid
向量似乎不会运行它们的析构函数。
我试过了:
grid.clear()
erase/remove
使用pop_back
什么是存储/返回它们的更好方法,以便在grid
被销毁时,包含的Blocks
也将被删除。
答案 0 :(得分:4)
好的,所以如果你想要一个更好的方法,可以做一些改变:
static
s!在这里根本不需要它们。首先,一个容器不可能从另一个容器中删除元素,除非它在某种程度上引用了它。您可以创建一个变量来保存块的所有容器,并使用 从每个容器中删除块,但是......是的。
在这种情况下,只要您记住其含义,就可以接受弱参考解决方案。
std::shared_ptr
所有权和std::weak_ptr
参考创建一个std::set<shared_ptr<Block>> blocks;
,然后创建两个带弱引用的容器;可能被称为allBlocks
或grid
或其他。那些弱引用集合可以是例如std::set<std::weak_ptr<Block>>
。
现在,当从grid
或allBlocks
中删除元素时,您需要将其从blocks
中删除。要对它进行查找,你需要这样的东西:
struct null_deleter {
void operator()(void const *) const { }
};
为集查找正确创建值。然后,当迭代任何其他容器时,您需要在ptr.expired()
引用上使用weak_ptr
,以查看它是否先前已被删除。
该想法的警告是原始shared_ptr
不是共享;该类仅用于方便weak_ptr
和自动销毁。
std::unique_ptr
所有权和int
参考另一种更简单的方法是使用std::unordered_map
并为每个块创建一个“唯一ID”键。
std::unordered_map<unsigned, std::unique_ptr<Block>> blocks;
现在你的容器必须是std::set<unsigned>
,查找看起来像是:
for (auto b : grid) {
auto bIt = blocks.find(b);
if (bIt != blocks.end) {
// do things with *bIt
} else {
// e.g. add the b to the "delete list"
}
}
现在您可以处理“删除列表”并从容器中删除死ID。
由于使用起来可能会很繁琐,一个好主意可能是将set
包装到一个容器中,该容器会在返回begin()
或end()
之前进行清理,以便在Block中进行自定义迭代值。
类似地,这种包装结构的析构函数可以从地图中删除值,从而有效地使所有其他容器中的所有id悬空。
这当然会引发线程安全问题,因为原始blocks
映射需要在整个迭代中被锁定;至少是为了修改。让cbegin()/cend()
允许两个线程从同一个共享map
读取,但是......在线程之间共享数据时出现的问题超出了这篇文章的范围。
我想到的另一个想法有时被称为“中毒”。在这种情况下,您不需要主容器;两个常规容器都会将shared_ptr
保存到Blocks ...并且有一个扭曲。
当选择一个块进行删除时,会在其上设置一个特殊标志。它变得“中毒”,每个容器都应该在迭代之前扫描这些块。
如果每个容器确实如此,那么对Block die及其析构函数的所有引用都将正确启动。您实际上是通过它的特殊值来传达命令。
如果你不想修改Block类,那么拥有std::shared_ptr<std::optional<Block>>
并且使optional
无效可以正常工作,除了Block的析构函数会立即运行,而不是最后一次运行结构决定进行扫描。根据您的目标和需求,这可能会更好或更差。