【发布时间】:2019-08-27 11:54:27
【问题描述】:
我正在编写一个需要高效函数来过滤成员容器的类(比如说std::vector)。这个函数应该有类似下面的接口:
void filter(std::vector<SomeType>& items, const std::vector<int>& inds);
该函数应使容器items 处于以下状态:
- 应删除索引从inds 指向的项目
- 其他物品应保留在容器中,保持初始顺序。
为简单起见,我们假设 inds 是一个完美的容器,每个操作的 O(1) 都为 O(1),并且所有索引都有效且没有重复。
我的想法是创建第二个容器,保留所需空间,然后将未被inds 索引的每个元素移动(通过std::move)到这个新容器中;然后只需交换旧容器和新容器。
例如这样:
void filter(std::vector<SomeType>& items, const std::vector<int>& inds)
{
std::vector<SomeType> new_items{};
new_items.reserve( items.size() - inds.size() );
for(size_t i = 0; i < items.size(); ++i)
if( contains( inds, i ) ) // magic O(1) function, never mind
new_items.push_back( std::move( items[i] ) );
items.swap(new_items);
}
我的问题是:
1) 在vector(或通常任何其他标准容器)内的某些元素上使用std::move 后,是否会出现诸如双重破坏这些元素之类的问题?
2) 有没有一种标准方法可以有效地进行此类过滤?
【问题讨论】:
-
你不需要两个向量,因为你只是删除,所以你可以在删除最后一个剩余项目之后移动第一个项目,并从那里继续复制所有不被删除的项目,并跳过应该删除的项目。如果您的向量非常大(将内存使用量减半),或者您只删除少数项目,即最初跳到要删除的第一个项目(不修改初始部分),这可能会稍好一些(不修改初始部分)可能会节省一小部分的时间。 IE。 12345678(减去 3 5 7)= 12468 -> 您可以安全地在原始“345678”上写“468”。
-
顺便说一句,
std::vector<T>本质上需要可以“移动”的类型(“T 必须满足 CopyAssignable 和 CopyConstructible 的要求。”),因为vector本身会重新分配整个缓冲区它用完了空间,并将所有值从一个内存缓冲区“移动”到新的缓冲区(通常在简单类型的情况下类似于 memmove,在更复杂类型的情况下进行复制分配)。 IE。如果您的SomeType已经可以在std::vector中使用,那么我认为std::move也应该适用(希望我没有忘记一些正式细节,为什么std::move在这种类型上可能会失败)。跨度>
标签: c++ containers stdmove