在堆上存储 3D 数组作为结构成员
Posted
技术标签:
【中文标题】在堆上存储 3D 数组作为结构成员【英文标题】:Storing 3D Array on Heap as Structure Member 【发布时间】:2021-08-28 13:07:07 【问题描述】:我最近开始使用 C++ 进行数值计算,我想在模拟过程中使用 Struct Operators
来存储 3D 场。
我用
const unsigned int RES = 256;
auto arr3D = new double [RES][RES][RES];
因为根据我的测试,这种方法比使用 Boost_multiarr、Eigen Tensor 或嵌套向量更快。
到目前为止,这适用于我的简约 Test.cpp,但是当我尝试将这些相同的 3D 数组实现为 Struct Operators
的成员时,我无法再使用 auto
命令:
const unsigned int RES = 256;
struct Operators
public:
std::complex<double>*** wfc; // edited, see 'spitconsumers' comment
Operators(Settings &set) // just another structure used by Operators
wfc = new std::complex<double> [RES][RES][RES];
// ...Initializing wfc using Settings
;
在这种情况下,我找不到声明 wfc
的方法,这样我就不会收到该类型的错误
错误:无法在赋值中将 'std::complex (*)[256][256]' 转换为 'std::complex***'
所以我的问题是如何正确声明 3D 数组wfc
以及维护这种结构方法是否完全可能/有用。如果wfc
不是结构的成员,访问wfc[i][j][k]
通常会更快吗? (我将不得不这样做〜10 ^ 6次)
提前致谢!
【问题讨论】:
我会跳过[][][]
语法,只使用一个向量。元素[z*RES*RES+y*RES+x]
将为您提供相当于[z][y][x]
。
【参考方案1】:
错误消息返回正确的声明,std::complex<double>(*wfc)[RES][RES];
。
const unsigned int RES = 256;
struct Settings ;
struct Operators
public:
std::complex<double>(*wfc)[RES][RES]; // edited, see 'spitconsumers' comment
Operators(Settings& set) // just another structure used by Operators
wfc = new std::complex<double>[RES][RES][RES];
// ...Initializing wfc using Settings
// Setting the last element
wfc[254][254[254] = 42;
;
【讨论】:
感谢您的解决方案,这正是我想要的!但是,当我测量每个i,j,k
使用for 循环进行T[ix][iy][iz] = std::pow(P[ix][iy][iz], 2) - n_L;
形式的操作所需的时间时,我发现'splitconsumer' 的解决方案快两倍。这是由于内存分配造成的吗?
@Azure27 听起来编译后的代码正在计算每次访问时的每个位置,这会非常慢,因为它需要两次乘法和 3 次加法才能获得偏移量。那将是糟糕的优化器性能。确保使用 -O3 在涉及数组乘法等交叉访问的其他问题上,指针数组方法通常较慢,因为处理器在 cpu 寄存器中的数学运算比指针访问快。【参考方案2】:
在您的错误消息中,编译器告诉您new complex [RES][RES][RES]
正在返回类型std::complex (*)[256][256]
。
double wfc
应该是std::complex*** wfc
。
必须知道类成员类型,并且由于在定义成员变量时没有对其进行初始化,因此编译器无法推断变量的类型,这就是auto
不能作为类成员类型工作的原因,当您没有立即为其分配某些内容时。但是您将值直接分配给测试程序中的变量,从而允许编译器在那里推断出类型。
此外,new
运算符返回一个指向未初始化 std::complex<double>**
指针数组的指针。您需要为所有未初始化的指针调用new
。
std::complex<double>*** wfc;
wfc = new std::complex<double>** [RES];
for(int i = 0; i < RES; i++)
wfc[i] = new std::complex<double>* [RES];
for(int j = 0; j < RES; j++)
wfc[i][j] = new std::complex<double> [RES];
for(int k = 0; k < RES; k++)
wfc[i][j][k] = /* insert default value here */;
【讨论】:
谢谢,这很有意义!将double
替换为std::complex<double>***
,我现在得到错误> 错误:无法转换'complex ()[256][256]' aka 'std::complexnew
语句返回一个指向未初始化指针数组的指针。您需要在所有未初始化的指针上运行调用 new
的 for 外观。我将编辑我的答案以完全解决您的问题(希望如此)。
for 循环*。不幸的错字。
非常感谢,这种方法效果很好!虽然它不像 dougs 解决方案那么短,但我在性能测试中发现,对于每个 i、j、k 的 T[ix][iy][iz] = std::pow(P[ix][iy][iz], 2) - n_L;
等元素操作,它的速度是它的两倍。这是否与内存分配方式有关?以上是关于在堆上存储 3D 数组作为结构成员的主要内容,如果未能解决你的问题,请参考以下文章