97

既然存在std::liststd::vector那么有理由在 C++ 中使用传统的 C 数组,还是应该避免使用它们,就像malloc

4

11 回答 11

109

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

于 2012-05-23T10:30:09.030 回答
85

当然,尽管std::array在 C++11 中,实际上仅适用于静态数据。C 风格的数组与 相比具有三个重要优点 std::vector

  • 它们不需要动态分配。出于这个原因,在您可能有很多非常小的数组的情况下,首选 C 样式数组。说一个像 n 维点这样的东西:

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

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

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

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

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

  • 最后,与上述相关,编译器可以从初始化器中计算出数组的实际大小。您不必计算它们。

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

于 2012-05-23T11:32:37.617 回答
15

永远不要说“从不”,但我同意他们的角色被 STL 的真实数据结构大大削弱了。

我还要说对象内部的封装应该尽量减少这样的选择的影响。如果数组是私有数据成员,您可以将其换入或换出,而不会影响您类的客户。

于 2012-05-23T10:29:22.907 回答
11

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

于 2012-05-23T10:32:56.947 回答
6

arrayinc++为您提供固定大小的快速替代动态大小std::vectorstd::list. std::arrayc++11. 它提供了 std 容器的好处,同时仍然提供了 C 样式数组的聚合类型语义。

因此,在需要的地方,c++11我肯定会std::array在向量上使用 。但我会避免在C++03.

于 2012-05-23T10:34:14.790 回答
4

大多数情况下,,我想不出使用原始数组的理由,比如说,vectors如果代码是新的

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

于 2012-05-23T10:29:52.383 回答
4

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

于 2012-06-10T16:22:09.417 回答
3

我想说数组仍然有用,如果您要存储少量静态数据,为什么不呢。

于 2012-05-30T02:52:20.513 回答
2

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

于 2012-05-23T10:49:27.027 回答
2

C 风格的数组是一种基本的数据结构,因此在某些情况下使用它会更好。然而,对于一般情况,使用更高级的数据结构来修整基础数据的角落。C++ 允许你用内存做一些非常有趣和有用的事情,其中​​许多都适用于简单的数组。

于 2012-05-23T11:50:01.207 回答
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 样式的字符串。

于 2013-01-23T09:26:23.813 回答