【发布时间】:2012-06-27 23:03:11
【问题描述】:
我知道 clear() 操作的复杂性与容器的大小成线性关系,因为必须调用析构函数。但是原始类型(和 POD)呢?似乎最好的办法是将向量大小设置为 0,以便复杂度保持不变。
如果可以的话,std::unordered_map 也可以吗?
【问题讨论】:
标签: vector complexity-theory unordered-map primitive
我知道 clear() 操作的复杂性与容器的大小成线性关系,因为必须调用析构函数。但是原始类型(和 POD)呢?似乎最好的办法是将向量大小设置为 0,以便复杂度保持不变。
如果可以的话,std::unordered_map 也可以吗?
【问题讨论】:
标签: vector complexity-theory unordered-map primitive
似乎最好的办法是将向量大小设置为 0,这样复杂度就恒定了。
一般来说,resizing a vector to zero 的复杂度与vector 中当前存储的元素数量呈线性关系。因此,将vector 的大小设置为零比调用clear() 没有任何优势——两者本质上是相同的。
但是,至少有一种实现(libstdc++,bits/stl_vector.h 中的源代码)通过使用部分模板特化为原始类型提供了 O(1) 复杂度。
clear() 的实现导航到bits/stl_construct.h 中的std::_Destroy(from, to) 函数,该函数执行非平凡的编译时优化:它声明了一个辅助模板类_Destroy_aux,模板参数类型为@ 987654335@。该类对true 有一个部分特化,对false 有一个显式特化。两种特化都定义了一个名为__destroy 的静态函数。如果模板参数为true,则函数体为空;如果参数是false,则调用body contains a loop invoking T's destructorstd::_Destroy(ptr)。
诀窍来了line 136:
std::_Destroy_aux<__has_trivial_destructor(_Value_type)>::
__destroy(__first, __last);
辅助类是根据__has_trivial_destructor 检查的结果实例化的。检查器为内置类型返回true,为具有非平凡析构函数的类型返回false。因此,对 __destroy 的调用对于 int、double 和其他 POD 类型将变为无操作。
std::unordered_map 与 vector 的不同之处在于它可能需要删除代表 POD 对象的“哈希桶”的结构,而不是删除对象本身*。 clear 到 O(1) 的优化是可能的,但是很大程度上依赖于实现,所以我不会指望它。
* 确切答案取决于实现:基于开放寻址(线性探测、二次探测等)实现collision resolution 的哈希表可能能够删除O(1) 中的所有桶;但是,基于单独链接的实现必须一个接一个地删除存储桶。
【讨论】:
resize来说是真的吗?
gcc 的std::_Destroy 版本,clear() 最终使用的版本,尝试对类型是否具有微不足道的析构函数进行模板化,因此在这种情况下,即使没有优化通过,复杂性也是恒定的。但是我不知道模板的效果如何。
【讨论】: