在堆上存储 3D 数组作为结构成员

Posted

技术标签:

【中文标题】在堆上存储 3D 数组作为结构成员【英文标题】:Storing 3D Array on Heap as Structure Member 【发布时间】:2021-08-28 13:07:07 【问题描述】:

我最近开始使用 C++ 进行数值计算,我想在模拟过程中使用 Struct Operators 来存储 3D 场。 我用

在堆上创建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&lt;double&gt;(*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&lt;double&gt;** 指针数组的指针。您需要为所有未初始化的指针调用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&lt;double&gt;***,我现在得到错误> 错误:无法转换'complex ()[256][256]' aka 'std::complex ()[ 256][256]' to 'complex***' aka 'std::complex***' in assignment wfc = new complex [RES][RES][RES]; new 语句返回一个指向未初始化指针数组的指针。您需要在所有未初始化的指针上运行调用 new 的 for 外观。我将编辑我的答案以完全解决您的问题(希望如此)。 for 循环*。不幸的错字。 非常感谢,这种方法效果很好!虽然它不像 dougs 解决方案那么短,但我在性能测试中发现,对于每个 i、j、k 的 T[ix][iy][iz] = std::pow(P[ix][iy][iz], 2) - n_L; 等元素操作,它的速度是它的两倍。这是否与内存分配方式有关?

以上是关于在堆上存储 3D 数组作为结构成员的主要内容,如果未能解决你的问题,请参考以下文章

C# 中的静态结构存储在哪里?

你可以在结构中有一个类吗?

类和结构体的区别

数据结构之数组

c ++ - 使用存储在堆上的数组填充对称矩阵

使用堆上结构的结构初始化语法