【问题标题】:Accessing elements of a double std::array访问双 std::array 的元素
【发布时间】:2023-03-28 17:58:01
【问题描述】:

我的问题是关于访问双 std::array 元素的效率。由于std::array 是一个静态大小的容器,我希望它的数据存储在一个连续的内存块中,并且访问std::array 的元素与C 样式数组相同。使用std::array 不应增加任何额外开销。

访问双精度数组std::array<std::array<T,N>,M> 的元素是否已优化?

例如我必须在下面提供源代码。

#include <array>
#include <random>

int main(){
  std::array<std::array<int,4>,2> a;

  for(int j=0;j<4;j++)
    a[0][j] = rand();

  for(int j=0;j<4;j++)
    a[1][j] = rand();

  int r = a[0][1] + a[1][3];
  return r;
}
  1. a 是否使用单个内存块?
  2. 访问具有常量索引的元素(即a[1][3])是内存中的单次移位还是双次移位?
  3. 在循环中访问元素需要多少次移位(即a[1][j]

我在上面的例子中使用了 godbolt.org 来检查汇编代码,看起来gcc -O4做得很好。

例如访问a[1][3]a[0][1]被编译为:

    mov     eax, DWORD PTR [rsp+28]
    add     eax, DWORD PTR [rsp+4]

但是,我可以在更复杂的示例中使用此发现吗? 还是我应该坚持简单的std::arrays来控制访问效率?

std::array中是否有任何ISO标准描述?

【问题讨论】:

  • 你所说的“记忆转移”是什么意思?您确定您没有进行通常很糟糕的过早优化吗?您是否测量(或分析或基准测试)这是您程序中的瓶颈?首先要专注于编写编写良好、可读性强、易于理解、可维护和工作的代码。 那么如果“性能”不符合您衡量和分析的现有要求,以找到热点和瓶颈,并将您的优化工作集中在重要的地方,并提供大量文档和了解你在做什么。
  • 使用std::vector 除非您需要std::array 用于某些明确的目的。并在考虑优化之前进行测量。查看为具有分支预测、乱序执行、推测执行等的现代 CPU 生成的代码几乎毫无意义,除非您已经具备非常专业的知识。
  • 没有-O4。但是std::arrays 是一个连续的块。
  • @Someprogrammerdude 使用术语“内存转移”我试图总结我们在 std::vector&lt;std::vector&lt;T&gt;&gt; 中所做的双重查找。我的问题不是关于优化我的来源。这是关于std::array的定义和描述。

标签: c++ arrays c++11 stl


【解决方案1】:
  1. 是的,它位于连续的内存块中
  2. 在优化甚至非优化代码中不涉及移位(除了可能用于索引一维数组的简单移位之外)。 std::array 与常规 C 样式数组的不同之处在于,编译器无法确定数组在内存中的布局方式(即行是第一个还是列,大多数编译器按行顺序排列,但是这并不重要),如何解决索引(是否涉及任何乘法“移位”)等。它是一个简单的一维数组,其中每个元素都是给定的类型(在您的情况下,每个元素都是一个数组本身)。下面的例子应该证明我在说什么。
  3. 无班次,见上和下

#include <iostream>

using std::cout;
using std::endl;

template <int size>
using int_arr = int[5];

int main() {
    // an array of 5 arrays, unlike int arr[5][5]; 
    int_arr<5> arr[5];

    // first operator[] will resolve to the first array, return a 
    // reference to it and then the second will resolve to the correct
    // integer.  Similar to ((arr[0])[0])
    arr[0][0] = 12;
    cout << arr[0][0] << endl;

    return 0;
}

【讨论】:

  • 谢谢。在我的示例中,访问a[1][3] 编译器转换为mov eax, DWORD PTR [rsp+28],这与您在 2 中描述的不同
  • @ztik 那是编译器优化您从[rsp+16] 的访问(从起始位置获取一个数组,然后[rsp + 12] 将第二级数组中的第三个整数获取到一条指令。它在概念上仍然与我在 2 中描述的相同
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-05-29
  • 1970-01-01
  • 1970-01-01
  • 2020-11-26
相关资源
最近更新 更多