使用 std::vector 的开销?

Posted

技术标签:

【中文标题】使用 std::vector 的开销?【英文标题】:Overhead to using std::vector? 【发布时间】:2013-02-24 00:07:46 【问题描述】:

我知道手动动态内存分配通常是个坏主意,但它有时是否比使用 std::vector 更好的解决方案?

举个粗略的例子,如果我必须存储一个 n 整数数组,其中n 来实现它

int* data = new int[n]; //assuming n is set beforehand

或使用向量:

std::vector<int> data;

使用std::vector 绝对是一个更好的主意,还是在实际情况下手动分配动态内存会是一个更好的主意,以提高效率?

【问题讨论】:

您不必push_backstd::vector&lt;int&gt;(n)几乎等同于您的动态数组版本,除了 n 整数是值,因此为零,在向量中初始化。 @juanchopanza:公平点。我删除了push_back 部分。它不应该成为比较的一部分。 【参考方案1】:

如果您事先知道大小(尤其是在编译时),并且不需要 std::vector 的动态调整大小功能,那么使用更简单的东西就可以了。

但是,如果你有 C++11,最好是 std::array,否则最好是 boost::scoped_array

我怀疑除非它显着减少代码大小或其他东西,否则效率会大大提高,但它更具表现力,无论如何都是值得的。

【讨论】:

【参考方案2】:

使用std::vector/std::array 总是更好,至少在您可以最终证明(通过分析)T* a = new T[100]; 解决方案在您的特定情况下要快得多。这不太可能发生:vector/array 是一个非常薄的层,围绕着一个普通的旧阵列。使用vector::at 进行边界检查会产生一些开销,但您可以使用operator[] 来规避这一点。

【讨论】:

使用 C 风格数组的通常原因与速度无关;它用于静态初始化,并且用于编译器根据初始化器的数量来确定大小。 (当然,这绝不适用于动态分配的数组)。 @James 如果我正确阅读了您的评论,您是否反对我似乎在抨击 C 样式数组而不说我的意思是动态分配的数组?如果是这样,我已经编辑了我的答案。 (另外,为您的回答 +1。) 这样就搞定了。我不知道vector/array是一个薄层。我有点假设,有了所有功能,它一定会有很大的开销。 您说“总是……直到……解决方案更快”。我没有将其视为仅限于动态分配。 (正如我在回答中所说,我从未使用过数组new。在std::vectorstd::string 之前,做的第一件事就是写一些等效的东西。)但是虽然我从来没有使用数组new,在某些情况下,C 样式数组是合理的(在 C++11 中,一些,但不是全部可以用std::array 替换)。【参考方案3】:

您应该尽可能避免C++ 中的C-style-arrays。 STL 提供的容器通常足以满足各种需求。想象一下对数组进行重新分配或从其中间删除元素。容器使您免于处理此问题,而您必须自己处理它,如果您没有这样做一百次,那很容易出错。 当然,一个例外是,如果您正在处理可能无法处理 STL-containers 的低级问题。

已经有一些关于这个话题的讨论。请参阅 SO 上的 here。

【讨论】:

+1 最后的链接,这应该一劳永逸地消除访问矢量元素缓慢的神话。【参考方案4】:

n在编译时是已知的,那么你应该选择std::array为:

std::array<int, n> data; //n is compile-time constant

如果n 在编译时未知,或者数组可能会在运行时增长,则选择std::vector

std::vector<int> data(n); //n may be known at runtime 

或者在某些情况下,您可能还更喜欢std::deque,它在某些情况下比std::vector 更快。见这些:

C++ benchmark – std::vector VS std::list VS std::deque

Using Vector and Deque 赫伯·萨特

希望对您有所帮助。

【讨论】:

除非您知道n 非常非常小,否则您可能不应该将局部变量声明为std::array。除非有一些非常具体的原因,否则我只会使用std::vector---如果我知道大小,我会用正确的大小初始化向量。 (这也假设该类型有一个默认构造函数。)【参考方案5】:

使用 std::vector 绝对总是一个更好的主意,还是在实际情况下手动分配动态内存会是一个更好的主意,以提高效率?

称我为傻瓜,但 99.9999...% 的时间我只会使用标准容器。默认选择应该是std::vector,但也应该是std::deque&lt;&gt; could be a reasonable option sometimes。如果在编译时知道大小,请选择std::array&lt;&gt;,这是一个轻量级、安全的 C 样式数组包装器,它引入了零开销。

标准容器公开成员函数以指定初始保留的内存量,因此您不会遇到重新分配的麻烦,也不必记住delete[]您的数组。老实说,我不明白为什么要使用手动内存管理。

效率应该不是问题,因为您可以使用 throwing 和 non-throwing 成员函数来访问包含的元素,因此您可以选择是偏向于安全性还是性能。

【讨论】:

【参考方案6】:

std::vector 可以使用 size_type 参数构造,该参数用指定数量的元素实例化向量并执行单个动态分配(与您的数组相同),您也可以使用 reserve 减少使用时间内重新分配的次数。

【讨论】:

【参考方案7】:

我想不出动态分配 C 风格的任何情况 矢量是有意义的。 (我在 C++ 中工作超过 25 年 年,我还没有使用new[]。)通常,如果我知道 预先确定尺寸,我会使用类似的东西:

std::vector<int> data( n );

获取一个已经确定大小的向量,而不是使用push_back

当然,如果n 非常小并且在编译时已知, 我将使用std::array(如果我可以访问 C++11),甚至 一个 C 风格的数组,只需在堆栈上创建对象,使用 没有动态分配。 (这种情况在国内似乎很少见 我工作的代码;小型固定大小的数组往往是 类。我偶尔会使用 C 风格的数组。)

【讨论】:

以上是关于使用 std::vector 的开销?的主要内容,如果未能解决你的问题,请参考以下文章

使用 std::vector 和内存释放

将使用 PIMPL 习语的类存储在 std::vector 中

为啥 std::vector::data() 中没有使用指针 typedef?

使用 std::vector 的指数内存消耗增长

错误使用 std::vector<std::string> myString

使用 2D std::vector 对 SYCL 进行矩阵乘法