对于可移动类型,删除std::向量中间的元素仍然很昂贵吗

Is deleting an element in the middle of a std::vector still expensive with movable types?

本文关键字:元素 向量 类型 可移动 删除 std 中间      更新时间:2023-10-16

通常认为删除std::vector中间的元素成本高昂,因为它需要在每个元素向下复制以填充孔。

对于C++11,std::vector向下移动所有元素,这应该非常快(如果只是与副本相关的话(,至少我认为是这样。当然,它在时间上仍然是线性的,但总的来说,它应该比旧版本更快。

这是真的吗?我再也不用担心删除中间的一些对象了吗?

这取决于向量中的内容。如果它是POD或指针,我无法想象它会有什么不同。如果它的类实例复制起来很重,但移动速度很快,我希望C++0x能加快速度。

然而,我认为,如果从std::vectors中间删除元素是代码中的一个瓶颈,那么C++0x可能不是正确的解决方案。考虑更好地处理此类情况的数据结构,或者如果元素的顺序无关紧要,则考虑std::iter_swapstd::vector::pop_back

如果考虑到标准使用的成本,它的成本也会一样高。该标准规定了对所包含类型执行的操作的成本,并且操作的数量仍然相同,只是每一个操作都会更快。

例如,在C++03中考虑在vector<string>中间插入元素的成本。标准调用O(N),其中N是矢量的大小,但实际成本是O(N * M),其中M是字符串的大小。在分析容器中的操作成本时忽略M的原因是它取决于所包含的元素。具有可移动类型的C++0x中的成本将是O(N)(字符串可以移动到新位置(,但在这两种情况下,公布的复杂性都将是O(N)

对于一个简单的反例,如果您认为在C++03中,在向量中间插入是一个昂贵的操作,并且您考虑std::vector<int>,那么在C++0x中,在矢量中间插入也同样昂贵,在这种情况下没有加速。

还要注意,任何潜在的改进都将取决于您的对象是可移动的(它们不需要是(,并且当前的一些STL实现已经以类似的方式进行了优化(没有语言支持(,例如,Dinkumware实现(我认为就是这个(有一些优化,当std::vector<std::vector<T> >增长时,它创建新的存储并用向量初始化(这些向量没有分配的内存,因此成本最小(,然后swap在旧的和新的分配区域中处理向量,有效地实现了移动语义。

实际上,在绝大多数情况下,移动要比复制快得多。任何具有通过引用存储的信息(否则必须复制(的类型都可以阻止复制——例如,几乎所有的容器、智能指针等,以及任何涉及这些类型的类。

当然,这仍然是线性时间,所以如果你有一百万个整数,它不会走得更快。然而,移动容器和智能指针之类的东西可能比复制它们快几个数量级。

我仍然是C++0x移动技术的新手,但我真的不知道如何在这里获得vector固有的有用加速。

这一切都取决于你的元素类型:我无法想象你会得到任何加速,除非你的元素类别的对象移动比复制快

第一点,即将决定您需要一个向量或列表?若您不希望对数据结构进行基于索引的访问,则列表会很好,因为您的删除发生在容器的中间。此外,你还必须考虑其他变体,如树,以决定最适合你的。这可能不会对您的性能产生太大影响,但仍然只是为了共享信息,列表中的内容有可能分布在多个页面文件中,因此使用大量数据会影响性能。

Rvalue引用和move构造函数可以提高容器的性能。它可以避免一些不必要的复制操作等。