快速初始化三维数组的方法(C++)

i2loujxw  于 2022-12-20  发布在  其他
关注(0)|答案(5)|浏览(185)

在我的程序中,我需要创建一个大的3d数组(~1GB)我目前使用两个for循环来初始化数组:

float*** array = new float** [m_width];

for (unsigned int i = 0; i < m_width; i++)
{
    array3d[i] = new float * [m_height];
    for (unsigned int j = 0; j < m_height; j++)
    {
        array3d[i][j] = new float[m_layers];
    }
}

代码运行良好,但速度非常慢。所以我的问题是:有没有更快的方法来初始化/保留多维数组的内存?(1d数组几乎可以立即创建)

7gyucuyw

7gyucuyw1#

你不是在创建一个3D数组,你是在创建一个1D数组的指针,每个指针指向一个1D数组的指针,每个指针指向一个1D数组的float,这在分配效率,缓存局部性,访问效率等方面是完全不同的。
如果你只创建一个大小为width * height * depth的数组,并使用索引算法来访问它,效率会高得多。记住,在C++中拼写“动态数组”的标准方法是std::vector;这对你来说尤其重要,因为vector对它的所有元素都进行了值初始化(对于float,这意味着将它们初始化为.0f)。

class Array3d
{
  size_t height, depth;
  std::vector<float> data;

public:
  Array3d(size_t width, size_t height, size_t depth) :
    height(height),
    depth(depth),
    data(width * height * depth)
  {}

  float& at(size_t x, size_t y, size_t z)
  { return data[x * height * depth + y * depth + z]; }

  float at(size_t x, size_t y, size_t z) const
  { return data[x * height * depth + y * depth + z]; }
};

根据个人喜好添加更多功能、安全检查等。
速度更快的原因:

  • 分配时:这只是对(相当昂贵的)动态分配机制的一次调用,而不是问题中的width * height + height + 1调用。
  • 访问时:这需要一些整数操作和一个指针解引用来获取任何数据成员。分离数组机制需要3个连续的内存获取(计算和偏移,获取那里的指针,偏移它,获取另一个指针,...)。
aor9mmx1

aor9mmx12#

从C++11开始,您可以使用以下代码:

int array[5][5][5] = {0};

这将创建一个3d数组,其中125个整数填充为零。恕我直言,这是在堆栈上创建和初始化3d数组的最快方式(就代码行而言)。
要在堆上创建一个(使用new),其他答案似乎也不错。
当然你必须填写你的数据后,这将需要一些时间,但它应该是可接受的快。

5gfr0r5j

5gfr0r5j3#

当我想避免多维数组初始化,但又想访问多维数组时,我采用的方法是:

#define IDX_3D(x, y, z, width, height) ((x) + (y) * (width) + (z) * (width) * (height))

void main()
{
    int width, height, depth;
    width = height = depth = 2;
    float* multi_array = new float[width * height * depth];

    multi_array[IDX_3D(1, 1, 1, width, height)] = 1.0f;
}
wfauudbj

wfauudbj4#

我认为有两种选择:
1.加载数组结构的文件。
1.使用线程来初始化,这个窗体在初始化时可能会使用更多的cpu。
你好。

sshcrbum

sshcrbum5#

正如另一个答案所说,这不是一个“块”数组,而是一堆指向已分配内存指针的已分配指针,你花了大量时间(N^2)分配元素,又花了大量时间分配指针数组,这是你为拥有不同大小的“行”所付出的代价,但显然这是你一开始就不需要的。
有一篇关于它的著名文章。
正如另一个答案所说,您需要分配一个内存块,并以大步前进的方式访问它。
一个明智的选择是使用一个为你做这件事的库。有很多库在那里,一个是Multi(免责声明,我是作者)。
您的代码将简化为:

multi::array<float, 3> arr({m_width, m_height, m_layers});

(add作为最后一个参数的值,以初始化为定义良好的值。)
幸运的是,您仍然可以使用与代码相同的语法(例如arr[1][2][3])* 访问元素 *。
完整代码:https://godbolt.org/z/fT1E7YbPG

相关问题