C++ C+中的二维动态分配+;使用具有空间局部性的新方法

C++ C+中的二维动态分配+;使用具有空间局部性的新方法,c++,new-operator,C++,New Operator,我很抱歉问了一个基本问题,但我真的找不到合适的答案。我继承了一个C++代码,其中的一部分有一个2D分配函数 AlLoaDe2D2/代码>: float** Allocate2D(long long sizeX, long long sizeY) { float** p = new float*[sizeY]; p[0] = new float[sizeX*sizeY]; for (long long z = 0; z < sizeY; z++) {

我很抱歉问了一个基本问题,但我真的找不到合适的答案。我继承了一个C++代码,其中的一部分有一个2D分配函数<代码> AlLoaDe2D2/代码>:
float** Allocate2D(long long sizeX, long long sizeY)
{
    float** p = new float*[sizeY];
    p[0] = new float[sizeX*sizeY];

    for (long long z = 0; z < sizeY; z++) {
        p[z] = p[0] + z * sizeX;
    }
    return ptr;
}

int main(){
    long long nX = ... ; 
    long long nY = ... ; 
    short** A = (short **)Allocate2D(nX, nY);
    // do stuff with A ...
}
float**Allocate2D(long-long-sizeX,long-long-sizeY)
{
浮动**p=新浮动*[sizeY];
p[0]=新浮点数[sizeX*sizeY];
用于(长z=0;z
关于这一点,我有两个问题:

1-是否
Allocate2D
创建一个大小为
sizeX
x
sizeY
的二维数组

2-当为
float**
定义
Allocate2d
时,这种分配二维
short
数组(如
a
)的常见/合法/良好做法是什么

  • 对。这取决于“2D数组”的确切含义。有多种方法可以创建用于存储按二维索引的数据的数据结构。人们可以用两个维度取消对
    A
    的引用,如
    A[y][x]
    中所述,它将按预期工作。此外,
    a[0]
    中还有一个指针,指向一个连续的sizeX sizeY float数组,其中x维度变化最快。这是使用
    float B[sizeY][sizeX]
    也可以得到的内存布局。然而,
    A
    B
    的类型(忽略浮动与短)并不相同
    A
    是指向指针数组的指针,而
    B
    则衰减为指向浮点的指针

  • 不。将指针强制转换为指向其他类型是不合法的。它打破了指针别名规则。此外,由于
    sizeof(float)
    几乎肯定不等于
    sizeof(short)
    ,因此数组的大小将是错误的,即它将是
    nX*2×nY
    。然而,由于
    float*
    从未被解引用为
    float
    ,我们可以清楚地看到,浮点指针的生命周期非常有限,因此实际上不会有问题

  • 因此,这将起作用,而不是数组的大小是其应有大小的两倍。但是,将浮点指针转换为短指针并不是严格合法的,而且很难看。编写一个类型正确的函数模板会好得多,而且非常简单

  • 对。这取决于“2D数组”的确切含义。有多种方法可以创建用于存储按二维索引的数据的数据结构。人们可以用两个维度取消对
    A
    的引用,如
    A[y][x]
    中所述,它将按预期工作。此外,
    a[0]
    中还有一个指针,指向一个连续的sizeX sizeY float数组,其中x维度变化最快。这是使用
    float B[sizeY][sizeX]
    也可以得到的内存布局。然而,
    A
    B
    的类型(忽略浮动与短)并不相同
    A
    是指向指针数组的指针,而
    B
    则衰减为指向浮点的指针

  • 不。将指针强制转换为指向其他类型是不合法的。它打破了指针别名规则。此外,由于
    sizeof(float)
    几乎肯定不等于
    sizeof(short)
    ,因此数组的大小将是错误的,即它将是
    nX*2×nY
    。然而,由于
    float*
    从未被解引用为
    float
    ,我们可以清楚地看到,浮点指针的生命周期非常有限,因此实际上不会有问题


  • 因此,这将起作用,而不是数组的大小是其应有大小的两倍。但是,将浮点指针转换为短指针并不是严格合法的,而且很难看。编写一个类型正确的函数模板会好得多,也很容易。

    值得理解的技术点是,没有2D数组这样的东西。您有一个指向浮点数的指针数组(因此为
    **
    ),每个指针都指向自己的浮点数数组。这是一个“数组数组”。我之所以提出这一点,是因为将它放入一个类中是一次性的工作,内存是连续分配的。好吧,代码就是这样。正在分配一个指针数组和一个大的
    float
    s数组(如果
    short
    的公共大小为16位,则数据太多)。
    float
    s数组被分成几行,每行分配给指针数组中的一个指针,然后可以像二维数组一样使用。这使数据保持良好的连续性,并且通常比单独对每一行进行
    new
    ing(搜索词:空间局部性)提供了显著的性能优势。这比内存分散在所有位置的最坏情况要好,但此解决方案有一个冗余的指针数组和指针跟踪。它还需要手动管理这两个分配,这可能比看起来要复杂得多。我上面链接的包装器类只有一个数组,该数组由
    std::vector
    管理,因此当您处理完它时,内存总是被放在一边(除非您特意不这样做),指针跟踪被一些非常简单的数学所取代。缺点是它看起来不像数组,你必须为它编制索引
    矩阵(x,y)
    ,而不是更熟悉的
    矩阵[x][y]
    。值得理解的技术点是,没有2D数组这样的东西。您有一个指向浮点数的指针数组(因此为
    **
    ),每个指针都指向自己的浮点数数组。这是一个“数组数组”。我之所以提出这一点,是因为将它放入一个类中是一项一次性工作,内存是连续分配的