当 T 是原始类型时, std::vector<T>::clear() 的复杂性是多少?
Posted
技术标签:
【中文标题】当 T 是原始类型时, std::vector<T>::clear() 的复杂性是多少?【英文标题】:What is the complexity of std::vector<T>::clear() when T is a primitive type? 【发布时间】:2012-06-27 23:03:11 【问题描述】:我知道 clear() 操作的复杂性与容器的大小成线性关系,因为必须调用析构函数。但是原始类型(和 POD)呢?似乎最好的办法是将向量大小设置为 0,以便复杂度保持不变。
如果可以的话,std::unordered_map 也可以吗?
【问题讨论】:
【参考方案1】:似乎最好的办法是将向量大小设置为 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
来说是真的吗?
@Quimby 是的。 clear 重用了向下调整向量大小的逻辑。【参考方案2】:
gcc 的std::_Destroy
版本,clear()
最终使用的版本,尝试对类型是否具有微不足道的析构函数进行模板化,因此在这种情况下,即使没有优化通过,复杂性也是恒定的。但是我不知道模板的效果如何。
【讨论】:
以上是关于当 T 是原始类型时, std::vector<T>::clear() 的复杂性是多少?的主要内容,如果未能解决你的问题,请参考以下文章
std::vector<std::array<T, N>> 或 std::array<std::vector<T>,N> 类型的数组如何存储在内存中?
调整 std::vector<std::unique_ptr<T>> 大小的性能