重新初始化向量的最快方法是什么?

Ben*_*Ben 1 c++ performance c++11

将大向量的所有值重置为其默认值的最快方法是什么?

struct foo
{
  int id;
  float score;
};

std::vector<foo> large_vector(10000000);
Run Code Online (Sandbox Code Playgroud)

最简单的方法是创建一个新的向量,但是我想重新分配内存要比重新初始化一个现有的向量花费更多的时间?

在重置之前,我必须遍历向量以收集非零分数(可能是数千或数百万)。我应该在此循环中逐个重置结构吗?

编辑:

向量大小是固定的,对于每个结构成员(所有浮点数和整数),“默认值”表示0。

Ala*_*les 6

为了确定最快的方法,您需要运行一些基准测试。

有多种不同的方法可以“重新初始化”向量:

  1. 调用clear(),对于简单类型,这应该大致相当于只是做vector.size = 0。向量的容量不会改变,也不会释放任何元素。如果元素存在,将会调用析构函数。当您或向量时,旧值将被覆盖push_backemplace_backresize
  2. 打电话assign(),例如large_vector.assign( large_vector.size(), Foo() );。这将迭代整个向量,将每个元素重置为其默认值。希望编译器能够将其优化为 memset 或类似的。
  3. 由于您的类型很简单,如果您只想将每个元素重置为0您应该能够执行 a memset,例如:memset( large_vector.data(), 0, sizeof(Foo)*large_vector.size() );
  4. 调用std::filleg std::fill( large_vector.begin(), large_vector.end(), Foo() );,这应该类似于assignor memset

  • 您的枚举缺少 `std::fill` ,我希望它至少与 `std::memset` 一样高效(在这种情况下它很可能做同样的事情),但它是类型安全的,并且在 C++ 中比它更具可读性`std::memset`。人们有一种冲动想要使用不安全的 C 函数来获得最大性能,但这种冲动是不合理的:因为 `std::fill` 比 `std::memset` 拥有更多的信息,所以它至少总是可以表现得一样好。 (4认同)

Use*_*ess 5

重新初始化向量的最快方法是什么?

别。

只需通过调用记录向量没有有效条目的事实即可clear()。这样的优点是既可以(可能)是最佳的,又可以保证正确,也可以完美地表现出来。国际海事组织(IMO)除非概要分析显示实际需要,否则不考虑建议的替代方案。

您的元素类型微不足道,因此对于良好的质量实现,复杂度的线性上限实际上应该是恒定的-无需依次销毁每个元素。

没有释放内存,或者以后需要重新分配内存。

您只需要在ing 之后push_backemplace_back在写入向量clear()时使用,而不是使用operator[]

为了使它与第一次使用保持一致,请不要使用10000000个值构成的元素初始化向量,而要使用reserve(10000000)不进行初始化的预分配。

例如。

int main() {
  vector<foo> v;
  v.reserve(10000000);

  while(keep_running) {
    use(v);
    v.clear();
  }
}

// precondition: v is empty, so
// don't access v[i] until you've done
//   v.push_back({id,score})
// at least i+1 times
void use(vector<foo> &v) {
}
Run Code Online (Sandbox Code Playgroud)

由于您需要就地将元素归零,因此第二快的通用解决方案可能是将上述循环更改为

  while(keep_running) {
    v.resize(10000000);
    use(v);
    v.clear();
  }
Run Code Online (Sandbox Code Playgroud)

或删除clear()并用于fill()就地覆盖所有元素。

如果非零元素稀疏(例如,基于某个有意义的索引进行更新),则在主循环遍历向量时,将它们动态归零可能会更快。

同样,您确实需要进行概要分析,以找出哪种方法更适合您的用例。


eer*_*ika 5

\n

将大向量的所有值重置为其默认值的最快方法是什么?

\n
\n\n

取决于向量的“默认值”意味着什么。

\n\n

如果要删除所有元素,最有效的是std::vector::clear.

\n\n

如果您想保留向量中的所有元素但设置它们的状态,那么您可以使用std::fill

\n\n
std::fill(large_vector.begin(), large_vector.end(), default_value);\n
Run Code Online (Sandbox Code Playgroud)\n\n
\n\n

如果元素类型很简单,并且“默认值”为零\xe2\x80\xa0,则std::memset可能是最佳的:

\n\n
static_assert(std::is_trivially_copyable_v<decltype(large_vector[0])>);\nstd::memset(large_vector.data(), 0, large_vector.size() * sizeof(large_vector[0]));\n
Run Code Online (Sandbox Code Playgroud)\n\n

为了验证是否std::memset值得这么麻烦,您应该进行测量(或检查装配)。优化器可以为您完成这项工作。

\n\n

\xe2\x80\xa0零意味着所有位都未设置。C++ 不保证这是零浮点数的表示。如果您的非最小用例使用指针,它也不保证它是空指针。

\n

  • 如果元素类型很简单,人们会希望将 `std::fill` 实现为 `memset` (但不会弄乱它)。事实上,这就是 [clang 所做的](https://godbolt.org/z/gbYf7S),但是(没有进一步的架构知识)我怀疑 gcc 的循环更糟。 (3认同)