如果我使用 Array 而不是 Vector,有啥缺点吗?

Posted

技术标签:

【中文标题】如果我使用 Array 而不是 Vector,有啥缺点吗?【英文标题】:Is there any disadvantages if I'm using Array instead of Vector?如果我使用 Array 而不是 Vector,有什么缺点吗? 【发布时间】:2012-11-26 08:54:48 【问题描述】:

我用 C++ 编写了一个 MPC 控制器,其中包括一个 Matrix 类,我将数据存储在一个数组中,并使用了 C 内存函数(memcpy、memset 等)。今天我用c ++向量替换了数组,并使用了复制来移动内存等......我遇到了一个问题,通过用向量替换数组,使用向量控制信号的计算时间几乎翻了一番。

如果我使用 alloc、memcpy、memset、free ins c++ 代码有什么缺点吗?如果有的话,那些是什么?

【问题讨论】:

当您注意到性能下降时,是在调试版本还是发布版本中?你的优化设置是什么?您是否偶然通过值而不是通过引用(在 C 样式代码使用指针的地方)传递新向量,从而产生了不必要的副本? 【参考方案1】:

Vector在两个方面增值:

    提供C 数组中不存在的附加功能,例如调整大小、检查当前大小等。您可以从它的界面中找到更好的替代方案来满足您的自定义解决方案。 捕获一些错误,例如寻址超出vector 范围的地址。

如果您对专有数据管理感到满意并对代码质量充满信心,则不需要vector。但是请注意,这可能会导致一些软件问题,例如与vector 相比,C 数组的可维护性降低(例如,即使您当前的代码没有,未来的代码也可能会访问超出范围的值)。

编辑: 请参阅@Als 答案以了解您的情况可能的替代方案 (std::array)。

【讨论】:

#2 仅在通过std::vector::at() 使用时有效,通过std::vector::operator []() 使用不执行边界检查。【参考方案2】:

使用手动内存管理意味着您有更多工作要做。因此你有更多的机会犯错误。

在 C++ 中,手动内存管理几乎总是错误的。如果你真的需要一个裸数组,你至少应该使用像boost::scoped_arrayboost::shared_array 这样的包装器。还可以使用std::unique_ptr 来管理数组。

【讨论】:

【参考方案3】:

如果您要插入或删除许多对象,则向量有 1 个主要(相对而言)问题,除了在此处无关的向量的开头/中间插入的情况(数组也有同样的问题)。

如果您要完成大量插入操作,通常会在插入操作之前添加对 reserve 的调用。称它为vector.reserve(<best guess number of objects to be inserted>)

这是因为,如您所知,vector 会根据需要分配内存。如果您一次插入大量项目,则可能涉及大量重新分配/复制,这可能会消耗大量时间。

这个问题还有其他解决方案。一种是使用 std::deque 在这种情况下效率更高一些,因为它不会每次都复制整个向量。或者使用 std::array,它是一个围绕 C 数组的矢量样式包装器。

编辑:标题已更改,但此信息可能仍然有用..

【讨论】:

这不是一个真正的问题,因为你也有一个 C 数组。更糟糕的是:对于 C 数组,您必须提供大小; std::vector 只是一个可选的优化。 比较向量(带保留)和数组不是问题。这更多是 OP 可能没有意识到的问题。如果是这样,这很可能是他放缓的原因【参考方案4】:

如果您在编译时已经知道数组的大小,请使用数组,实际上std::array 是更好的选择,但如果您需要动态数组,则最好使用std::vector

如果我使用 Array 而不是 Vector,有什么缺点吗?

数组很可能会为您提供更好的性能,因为不需要像std::vector 那样的额外间接。

但是,请注意,在大多数情况下,性能优势在大多数情况下并不显着,除非您的分析器指出这是一个问题。

如果我使用 alloc、memcpy、memset、free ins c++ 代码有什么缺点吗?如果有的话,那些是什么?

您绝对不应该在 C++ 中使用 c 风格的内存分配和管理函数。缺点是:

对于 C++,您根本不应该使用动态分配,除非它们无法避免。您应该使用智能指针。这正是 C++ 提供它们的目的。 此外,手动内存管理更容易出错。由于您使用的是 C++,因此代码的未来维护者可能只是假设您使用了 new 并在 malloced 指针上调用 delete,从而导致 UB。 使用 c 样式函数的另一个缺点是,与 new 不同,它们不调用对象构造函数,这会使您的对象未初始化。

【讨论】:

如果可能,在 C 中也应该限制动态分配的使用。智能指针并非随处可用(例如内核、嵌入式)【参考方案5】:

std::vector 和原始数组之间需要注意的一个区别是,std::vector 将在复制时为元素调用复制构造函数和复制赋值运算符,而对于原始数组,您必须自己这样做(例如像“memcpy”这样的函数不会调用复制构造函数/赋值运算符)。

如果数组的元素是原始类型或 POD 类型(POD 类型,Plain Old Data,基本上是一个只有公共数据成员而没有基类的类或结构),那也没关系。

这种差异正是您使用原始数组获得更好性能的原因:进行的复制更少。 C++11 通过右值引用和移动构造函数/赋值运算符最小化了这个问题,但它仍然不太可能击败手动处理的内存。

但无论如何,直接在代码的任何地方处理内存都是一个坏主意:它可能导致内存泄漏、非异常安全代码,并使代码过长和复杂。您可以创建自己的专门为 POD 类型设计的数组类,这样您就可以获得像 std::vector 这样的数组类的便利性和安全性以及原始数组的效率。

【讨论】:

以上是关于如果我使用 Array 而不是 Vector,有啥缺点吗?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 std::array::size constexpr 具有简单类型(int,double,...)而不是 std::vector (GCC)?

如果我对数组使用 delete p 而不是 delete [] p 会有啥结果? [复制]

Numpy 的 array() 和 asarray() 函数有啥区别?

向量、矩阵和数组数据类型有啥区别?

二维向量和向量图有啥区别?

std::valarray 和 std::array 有啥区别