应该在C ++中使用数组吗?


Answers:


109

std::array可用的C ++ 11中,答案是“是的,应避免使用数组”。在C ++ 11之前,您可能需要使用C数组在自动存储中(即在堆栈上)分配数组。


3
但是,许多编译器仍然缺少C ++ 11支持。考虑到缺少std :: array,您将不得不决定何时使用一种方法而不是另一种方法
Nowayz 2012年

4
std :: array是一个模板,它会对构建时间和可能的代码大小产生影响,因为对于T,N的每种组合,模板都会重新实例化。
zvrba 2012年

std :: vector保证按标准进行数据对齐,因此几乎可以在任何地方使用。使用C ++ 11,实际上没有理由使用C数组。
尼尔斯2012年

16
@Nils数组也保证对齐。另外,自动存储分配(“堆栈”)比动态存储分配要快得多。如果我知道正好有 3个元素(例如,三角形的坐标),则没有理由使用向量。
zvrba 2012年

9
@zvrba-使用std :: array vs C数组时检查生成的程序集。完全没有区别。
Nemanja Trifunovic 2012年

85

当然,尽管std::array在C ++ 11中使用,但实际上仅用于静态数据。C样式数组具有以下三个重要优点 std::vector

  • 他们不需要动态分配。因此,如果您可能有很多非常小的数组,则首选C样式数组。说出类似n维点的内容:

    template <typename T, int dims>
    class Point
    {
        T myData[dims];
    // ...
    };
    

    通常,您可能会想到a dims会非常小(2或3), T内置类型(double),并且最终可能 std::vector<Point>包含数百万个元素。您绝对不希望3百万的数百万个动态分配。

  • 支持静态初始化。这仅是静态数据的问题,例如:

    struct Data { int i; char const* s; };
    Data const ourData[] =
    {
        { 1, "one" },
        { 2, "two" },
        //  ...
    };
    

    这通常比使用向量(和std::string)更可取,因为它避免了初始化问题的所有顺序。在执行任何实际代码之前,数据已预加载。

  • 最后,与上述内容相关,编译器可以从初始化程序计算数组的实际大小。您不必数数。

如果您可以使用C ++ 11,则std::array可以解决前两个问题,并且在第一种情况下,绝对应优先使用C样式数组。但是,它没有解决第三个问题,并且让编译器根据初始化程序的数量来确定数组的尺寸仍然是首选C样式数组的有效理由。


11
C样式的数组初始化还消除了重复自己的需要。int i[] = { 1, 2, 3 };继续与int i[] = { 1, 2, 3, 4 };array<int, 3>需要手动更改为array<int, 4>

10
@JoeWreschnig可以轻松忘记的更改。如果添加一个元素,编译器会抱怨,但是如果删除一个元素,最后将得到一个额外的0初始化元素。我仍然将C样式数组广泛用于此类静态数据。
詹姆斯·坎泽

3
第一句话没有道理。
康拉德·鲁道夫2012年

4
第三点可以通过使用一个make_array函数来优雅地解决,类似于make_pairetc。@R的提示。马丁尼奥·费尔南德斯(Martinho Fernandes)
康拉德·鲁道夫2012年

@KonradRudolph:当然可以。Andreas提出“数组应在C ++中使用吗?”,詹姆斯回答说:“当然,尽管std::array在C ++ 11中,[它们应该]实际上仅用于静态数据”。
乔恩·普迪

15

永远不要说“从不”,但我同意STL的真实数据结构会大大削弱它们的作用。

我还要说的是,将对象封装在内部应该可以最大程度地减少此类选择的影响。如果数组是私有数据成员,则可以在不影响类客户端的情况下将其交换入或交换出。


11

我曾在无法使用动态内存分配的安全关键系统上工作。内存必须始终在堆栈上。因此,在这种情况下,您将使用数组,因为大小在编译时是固定的。


8
在C ++ 11之前,我会同意的,但是std::array<T>在堆栈上分配,并且在原始数组上基本上没有开销。
111111 2012年

5
@ 111111-同意。但是我知道该行业中的一些人尚未迁移到C ++ 11
Ed Heal

我知道这就是为什么我不投票给你,但我认为boost有一个版本,也很容易推出自己的版本。
111111 2012年

6
但是在安全关键的系统中,您不使用新的编译器功能(未经测试),也不使用升压。
詹姆斯·坎泽

3
许多安全关键系统都是基于OLD编译器构建的,这些编译器甚至没有更新的编译器功能,因为更改工具链是一个缓慢而昂贵的过程,需要大量的文书工作,测试和认证。
Brian McFarland 2012年

6

array可以c++为您提供固定尺寸的动态尺寸std::vector和动态尺寸的快速替代方案std::liststd :: array是中的新增功能之一c++11。它提供了std容器的优点,同时仍然提供了C样式数组的聚合类型语义。

因此,在向量中c++11我肯定会使用std::array,在需要的地方。但是我会避免使用C样式数组C++03


4

通常,,我想不出使用原始数组的理由,例如vectors如果代码是新的

如果您的库需要与需要数组和原始指针的代码兼容,则可能不得不使用数组。


1
...但是自C ++ 03起,向量“实际上具有”一个数组,您可以通过指针访问该数组以进行读取或写入。因此,这涵盖了大多数需要数组指针的代码。只有在该代码分配或释放数组时才可以使用向量。
史蒂夫·杰索普

@SteveJessop您可以访问内部数组吗?
Luchian Grigore'5

1
@LuchianGrigore:vector.data()在C ++ 11或更低版本中&vector.front()
迈克·西摩

@Luchian:如果向量不为空,则可以使用指向元素的指针(如果为空,则可以将空指针和长度为0的值传递给任何接受a的边沿情况的明智编写的函数零大小的缓冲区)。C ++ 03中添加的向量连续性保证的唯一目的几乎是允许向量被面向指针的代码用作缓冲区。
史蒂夫·杰索普

1
@SteveJessop还有一个事实,就是很多人都认为它得到了保证,因此最好不要让他们失望。
詹姆斯·坎泽

4

我知道很多人指出std :: array用于在堆栈上分配数组,而std :: vector用于堆。但是似乎都不支持非本地对齐。如果您要使用SSE或VPX指令执行任何类型的数字代码(因此分别需要128或256字节对齐),C数组似乎仍然是您的最佳选择。


3

我要说的是数组仍然有用,如果您要存储少量静态数据,为什么不这样做。


2

std::vector我可以想到的一个数组(当然是包裹在可以在需要时自动处理其释放的东西)中的唯一优点是,vector它不能传递其数据的所有权,除非您的编译器支持C ++ 11并移动构造函数。


6
“向量无法传递其数据的所有权”-是的,在C ++ 03中,它可以使用swap
史蒂夫·杰索普

2

C样式数组是基本的数据结构,因此在某些情况下最好使用它。但是,对于一般情况,请使用更高级的数据结构来完善基础数据的角落。C ++允许您对内存做一些非常有趣和有用的事情,其中​​许多工作都与简单数组一起使用。


3
C样式数组比std::arrays 更基础吗?在许多情况下,两者都将编译为同一程序集。
大约

1
更根本的是,它更基础。您知道数组将要做什么,因为std :: array依赖于标准库,因此可能会有一些实现上的怪癖。
詹姆士·永利

1
@JamesWy​​nn不是。std::array具有基于静态数组的精确定义的语义。
康拉德·鲁道夫

1

您应在内部使用STL容器,但不应在不同模块之间传递指向此类容器的指针,否则最终将陷入依赖地狱。例:

std::string foo;
//  fill foo with stuff
myExternalOutputProc(foo.c_str());

是一个很好的解决方案,但不是

std::string foo;
//  fill foo with stuff
myExternalOutputProc(&foo);

原因是std :: string可以用许多不同的方式实现,但是c样式字符串始终是c样式字符串。


我想您想说的是:如果使用标准库的不同编译器/实现来创建它们,则不要将不同的对象代码链接在一起。确实是这样。这与原始问题有何关系?
jogojapan

这只是何时使用数组或STL容器的建议。使用容器构建数据,并将其作为数组传递。对于字符串的其他数据,您将具有诸如myExternalOutputProc(foo.rawPointerGet(),foo.count())之类的内容;
user877329 2013年

但是,仅当您在同一项目中组合标准库的不同实现时,才会出现这些问题。太疯狂了。在任何普通代码中,完全可以通过引用(例如,在C ++ 11中将其移动)传递给函数来传递矢量。
jogojapan

1
我碰巧喜欢插件
user877329 2013年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.