2013-01-17 69 views
3

我存储std :: unordered_set中的指针,因为我不想重复(我删除集合中的指针,所以如果有重复,我将尝试删除已删除的指针)。我循环重复这些集合,并且因为我知道std :: vector是循环最快的容器(连续内存),所以我想知道std :: unordered_set是否相同。是std :: unordered_set连续(如std :: vector)?

如果没有,会使用一个std ::向量,如果指针已被删除更快检查?

+2

如果你想知道,你应该对它进行基准测试。 –

+6

真的是你的瓶颈吗?你有个人资料吗? –

+1

你*手动*删除指针?即您在该容器内存储原始指针?如果容器是你的瓶颈,你经常访问它,如果你与那些原始指针混杂在一起,那么你会遇到内存管理问题,这些问题远远超过了你的'unordered_set'与'vector'的性能惩罚场景。尝试使用智能指针。也许'unique_ptr',你将不得不编写纯粹的邪恶代码来获得重复的那些;) –

回答

14

std::unordered_set连续?

集装箱的确切实施不是由标准的详细... 然而标准确实规定了一些行为,从而限制了实际的表示。

例如,要求std::unordered_set具有记忆稳定性:即使在添加/删除其他元素时,元素的引用/地址也是有效的。

实现此目的的唯一方法是通过独立分配元素。用连续的内存分配是无法实现的,因为这样的分配必然是有限的,因此可能会过度增长而不可能在更大的块中重新分配元素。

+0

当插入或删除'unordered_set'中的其他元素(如果它导致重新散列)时,现有的迭代器将失效。 ?你确定你关于“记忆稳定”的陈述是正确的吗? –

+2

@AndrewTomazosFomomlingCorps,但重新哈哈哈特别不会使指针或引用无效。迭代器不一定直接指向内存,指针会这样做。元素不会在内存中移动,它们之间的连接(哪些迭代器遍历)可能会被重新调整,但元素不会移动。 –

+0

@JonathanWakely:在这种情况下,桶必须只是链接列表的头指针(链接哈希)。我认为这意味着每个插入都会导致动态内存分配。我认为将bucket的第一个元素放置在aligned_storage中会更高效。当然,这意味着你必须在重新编译时移动构造,而不是仅仅复制一个指针,但这与std :: vector是相同的“问题”。 –

3

不,它不是连续的内存,但它仍然非常快,这要归功于哈希映射。

编辑:快速随机访问,如果你主要做循环,你应该考虑另一个容器,我想。

编辑2:你应该配置文件以便知道是否值得考虑另一个容器。 (也许你应该优化别的地方......也许)。

1

的std :: unordered_set应该是一个哈希表容器,所以我们可以假设用的std ::向量比较时,它有一个小的性能损失。

但我认为你必须检查出实际的分析结果,如果unordered_set访问是真正的热点。

如果你正在使用的STL实现是合理的,它应该提供专业化一样的指针或者int类型的关键载体。如果这是真的,专用于指针类型的unordered_set的行为与自动增长/缩小向量非常相似,并且性能差异将不明显。

2

std::unordered_map提供以下成员函数的事实表明它基于散列表,可能是 separate chaining with linked lists

bucket_count, hash_function, load_factor, max_load_count, rehash 

元素是否连续取决于分配器。 unordered_maplist和该 缺省分配器不分配在连续的存储器中的 元件。每个元素的内存在插入时分配为 。

但是,您可以提供一个自定义分配器(例如pool allocator) ,它可以从预先分配的内存池中分配元素。尽管如此,数据结构中逻辑上相邻的元素在物理上可能不是 相邻的内存。

因此,如果循环遍历所有元素是最常见的操作,那么 ,unordered_map可能不是最佳解决方案。通过所有竞争解决方案的分析器运行主要用例将揭示最佳解决方案。

除此之外,unordered_map不是循环另一个 原因的最佳选择。注意单词“无序”的名称,它表明 - 不像list,vectormap-没有顺序的元素。例如,成员 函数rehash可能会更改元素的相对顺序。实际上,在任何操作期​​间,只要其负载因子 要超过max_load_factor,容器就会自动执行的重置。