【问题标题】:std::array vs array performancestd::array 与数组性能
【发布时间】:2015-07-27 14:27:33
【问题描述】:

如果我想构建一个非常简单的数组,比如

int myArray[3] = {1,2,3};

我应该改用std::array 吗?

std::array<int, 3> a = {{1, 2, 3}};

使用 std::array 比普通的有什么优势?它的性能更高吗?只是更容易处理复制/访问?

【问题讨论】:

  • 用 std:: 定义多维数组会很困难
  • @goGud:不难,只是更冗长。
  • 指针衰减、引用等...,很多关于 c 数组的事情都很奇怪。在 c 数组的情况下,迭代器可能是一个指针,for (auto i = ++std::begin(myArray); . . . 甚至可能无法编译(似乎基本类型的临时变量不是可变的,至少在 clang 6 中不是)
  • 初始化也神奇地不同:struct Direction { int32_t dw; int32_t dh; };static const Direction DIRECTIONS[DIRECTIONS_COUNT] { { -1, 1}, {0,1}, {1,1} , { 1, 0 }, {1,-1}, {0,-1} , {-1,-1}, {-1,0} }; 编译。但是,如果您更改为具有相同初始化程序列表的std::array&lt;Direction,DIRECTIONS_COUNT&gt;,您会突然收到“初始化程序太多”错误。 (VS 2019 社区语言 = C++17)
  • @Marc.2377 std::array 只是 C 样式数组的包装器。如果我没记错的话,在某些早期版本的 C++ 中,您无法使用单括号对其进行初始化。但是,不要相信我的话,因为我没有太多使用它们

标签: c++ c++11 stdarray


【解决方案1】:

使用std::array 与普通的相比有什么优势?

它具有友好的值语义,因此可以按值传递给函数或从函数返回。它的界面可以更方便地查找大小,并与 STL 风格的基于迭代器的算法一起使用。

性能更好吗?

应该完全一样。根据定义,它是一个简单的聚合,包含一个数组作为其唯一成员。

只是更容易处理复制/访问?

是的。

【讨论】:

    【解决方案2】:

    std::array 是一个非常薄的 C 风格数组的包装器,基本上定义为

    template<typename T, size_t N>
    struct array
    {
        T _data[N];
        T& operator[](size_t);
        const T& operator[](size_t) const;
        // other member functions and typedefs
    };
    

    它是一个aggregate,它允许您像使用基本类型一样使用它(即您可以按值传递、分配等,而标准 C 数组不能分配或直接复制到另一个数组) .你应该看看一些标准实现(从你喜欢的IDE跳转到定义或直接打开&lt;array&gt;),它是一个非常容易阅读和理解的C++标准库。

    【讨论】:

    【解决方案3】:

    std::array 被设计为 C 数组的零开销包装器,使其具有“正常”值,类似于其他 C++ 容器的语义。

    您应该不会注意到运行时性能的任何差异,同时您仍然可以享受额外的功能。

    如果您手头有 C++11 或 boost,则使用 std::array 而不是 int[] 样式数组是个好主意。

    【讨论】:

      【解决方案4】:

      性能更好吗?

      应该完全一样。根据定义,它是一个简单的聚合,包含一个数组作为其唯一成员。

      情况似乎更复杂,因为 std::array 与 C-array 相比并不总是产生相同的汇编代码,具体取决于特定平台。

      我在godbolt上测试了这个具体情况:

      #include <array>
      void test(double* const C, const double* const A,
                const double* const B, const size_t size) {
        for (size_t i = 0; i < size; i++) {
          //double arr[2] = {0.e0};//
          std::array<double, 2> arr = {0.e0};//different to double arr[2] for some compiler
          for (size_t j = 0; j < size; j++) {
            arr[0] += A[i] * B[j];
            arr[1] += A[j] * B[i];
          }
          C[i] += arr[0];
          C[i] += arr[1];
        }
      }
      

      GCCClang 为 C 数组版本和 std::array 版本生成相同的汇编代码。

      但是,

      MSVCICPC 会为每个数组版本生成不同的汇编代码。 (我用-Ofast-Os 测试了ICPC19;MSVC -Ox-Os

      我不知道为什么会这样(我确实希望 std::array 和 c-array 的行为完全相同)。可能采用了不同的优化策略。

      作为额外的一点: ICPC 中似乎有一个错误

      #pragma simd 
      

      在某些情况下使用 c 数组时进行矢量化 (c-array 代码产生错误的输出;std::array 版本工作正常)。

      不幸的是,我还没有一个最小的工作示例,因为我在优化一段相当复杂的代码时发现了这个问题。

      当我确定我没有误解有关 C-array/std::array#pragma simd 的某些内容时,我将向英特尔提交错误报告。

      【讨论】:

      • 可以认为是编译器的bug吗?
      【解决方案5】:

      std::array 具有值语义,而原始数组则没有。这意味着您可以复制 std::array 并将其视为原始值。您可以按值或引用作为函数参数接收它们,也可以按值返回它们。

      如果您从不复制std::array,则与原始数组相比没有性能差异。如果您确实需要制作副本,那么 std::array 会做正确的事情,并且仍然应该提供相同的性能。

      【讨论】:

        【解决方案6】:

        使用std::arrayc array 您将获得相同的性能结果 如果你运行这些代码:

        std::array<QPair<int, int>, 9> *m_array=new std::array<QPair<int, int>, 9>();
            QPair<int, int> *carr=new QPair<int, int>[10];
            QElapsedTimer timer;
            timer.start();
            for (int j=0; j<1000000000; j++)
            {
        
                for (int i=0; i<9; i++)
                {
                    m_array->operator[](i).first=i+j;
                    m_array->operator[](i).second=j-i;
                }
            }
            qDebug() << "std::array<QPair<int, int>" << timer.elapsed() << "milliseconds";
            timer.start();
            for (int j=0; j<1000000000; j++)
            {
        
                for (int i=0; i<9; i++)
                {
                    carr[i].first=i+j;
                    carr[i].second=j-i;
                }
            }
            qDebug() << "QPair<int, int> took" << timer.elapsed() << "milliseconds";
            return 0;
        

        你会得到这些结果:

        std::array<QPair<int, int> 5670 milliseconds
        QPair<int, int> took 5638 milliseconds
        

        Mike Seymour 是对的,如果你可以使用std::array,你应该使用它。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-05-26
          • 2013-11-10
          • 2011-05-24
          • 1970-01-01
          相关资源
          最近更新 更多