C++ - STL向量问题

3

有没有办法在保留+调整大小时加快std::vector的速度?

我希望能够达到与普通C数组相当的性能。

请参见以下代码片段:

TEST(test, vector1) {
   for (int i = 0; i < 50; ++i) {
      std::vector<int> a;
      a.reserve(10000000);
      a.resize(10000000);
   }
}

TEST(test, vector2) {
   for (int i = 0; i < 50; ++i) {
      std::vector<int> a(10000000);
   }
}

TEST(test, carray) {
   for (int i = 0; i < 50; ++i) {
      int* new_a = new int[10000000];
      delete[] new_a;
   }
}

前两个测试的速度是两倍慢(4095 ms vs 2101 ms),显然是因为 std::vector 在将其元素归零。 您有什么想法可以避免这种情况吗?

或者可能有一些标准的 (boost?) 容器,实现了基于堆的固定大小数组?

谢谢


3
为了让测试执行同等工作量,carray 测试需要在其中加入 for(std::size_t idx=0; idx<10000000; ++idx) new_a[idx]=0;。一旦加入后,我怀疑你不会发现明显的变化。 - sbi
1
我建议使用性能分析器,只有在性能低下时才进行优化。上述代码可能不会出现在普通应用程序中。通常情况下你不会这样做。也许最好的方法是创建自己的数组类以获得更多控制。 - INS
1
@Iulian:这是我想要能够对评论进行负面评价的评论之一。你为什么要创建自己的数组?你是否真的尝试过实现std::vector?你会发现,这非常难以得出一个既正确又快速的版本。 - sbi
@sbi 我认为这样的“基准测试”是不相关的。这就是为什么我们必须在真实应用程序上进行测试,而不是制作这种基准测试 - 这可能会导致性能即使使用“慢”的std::vector也是OK。如果他在这些地方发现性能问题,那么他可以考虑重写从std::vector中使用的部分,以浪费更少的CPU周期。此外,我认为上面的代码不太可能存在于一个真实应用程序中。我的原则是先让它工作,然后再让它变得更好/更快。 - INS
1
@lulian:这是一个好原则。然而@sbi在这里完全正确。STL是一个经过深思熟虑、设计良好的库,如果使用得当,将产生几乎与令人困扰的C对应库一样好的性能。创建自己的数组类将导致更多的时间花费在调试上,而不是可能在代码库的寿命内节省的时间。 - Alan
5个回答

11

正确,carray 版本并没有完全做到与向量版本相同的事情。std::vector<T>::reserve() 是这里的答案。 - rubenvb

2

不幸的是,它是基于堆栈的,例如,您甚至不能分配一个包含100万个整数的巨大数组而不更改堆栈大小。 - Yippie-Ki-Yay
一个 std::auto_ptr<boost::array<int>> 就可以完成这个任务。 - JoeG
@HardCoder1986:如果你想要一个基于堆的数组,std::vector 就是你需要的。修复你的测试,然后你会发现它与手动操作动态分配的 C 数组的速度完全相同。 - sbi

2

您的测试是在调试模式还是发布模式下执行的?我知道微软编译器会添加许多调试检查,这可能会极大地降低性能。


1
也许你可以使用一个boost::scoped_array,但如果这真的很关键的话,或许你应该尝试将初始化/分配放在最内层循环之外的某个地方?

1

我会给你一个机会,假设你已经进行了一些分析,并确定以这种方式使用向量是一个热点。如果没有,考虑差异还为时过早,除非你在一个非常紧密、小规模的应用程序中工作,在这种情况下,使用分析器甚至更容易,也有同样的理由这样做。

boost::scoped_array是一种解决方案。无法让向量不初始化存储的元素。另一个解决方案是std::deque,如果您不需要连续的内存块。deque可以比vector或具有相同数量元素的动态分配数组快得多,因为它创建较小的内存块,操作系统往往更好地处理它们,并且具有缓存友好性。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接