【问题标题】:What is the complexity of std::vector<T>::clear() when T is a primitive type?当 T 是原始类型时, std::vector<T>::clear() 的复杂性是多少?
【发布时间】:2012-06-27 23:03:11
【问题描述】:

我知道 clear() 操作的复杂性与容器的大小成线性关系,因为必须调用析构函数。但是原始类型(和 POD)呢?似乎最好的办法是将向量大小设置为 0,以便复杂度保持不变。

如果可以的话,std::unordered_map 也可以吗?

【问题讨论】:

    标签: vector complexity-theory unordered-map primitive


    【解决方案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() 最终使用的版本,尝试对类型是否具有微不足道的析构函数进行模板化,因此在这种情况下,即使没有优化通过,复杂性也是恒定的。但是我不知道模板的效果如何。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-04-24
      • 1970-01-01
      • 2012-04-06
      • 1970-01-01
      • 2014-05-07
      • 2017-09-01
      • 2014-07-02
      • 1970-01-01
      相关资源
      最近更新 更多