【问题标题】:How to properly manage dynamically allocated pointer arrays in C++?如何在 C++ 中正确管理动态分配的指针数组?
【发布时间】:2020-12-22 12:13:31
【问题描述】:

目前我正在开发一个只有小 RAM 容量 (128 MB) 的微处理器。我正在运行多个执行线程来分析性能,但问题的本质在于在动态空间中存储大量数据(浮点数和整数),以减少数据结构(如向量)倾向于的数据复制/分配的可能性在执行中依赖。

我决定测试一些可能的方案,以了解如何在 CLion 中解决这个问题。我写了以下代码:

#include <cstdlib>
#include <cstdio>


int initial_capacity = 3;
int current_capacity = 3;
int current_count  = 0;

int*** initializeArray(){
    // initialize triple array space in memory
    int*** arr;
    /*
       3 items -> 3 data sets -> each data set starts with 3 spaces
       a "int arr[3][3][3]" but dynamically allocated
    */
    arr = (int***) calloc(current_capacity, sizeof(int**));
    for(int i = 0; i < current_capacity; i++){
        arr[i] = (int**) calloc(current_capacity, sizeof(int*));
        for(int j =0; j < current_capacity; j++){
            arr[i][j] = (int*) calloc(current_capacity,sizeof(int));
        }
    }
    return arr;
}


void resizeArray(int *** arr){
    auto max = (double) current_capacity;
    double percentage = current_count/max;
    if(percentage >= 0.5){
        for (int i = 0; i < initial_capacity; ++i) {
            for (int j = 0; j < initial_capacity; ++j) {
                current_capacity*=2;
                arr[i][j] = (int*) realloc(arr[i][j],(current_capacity)*sizeof(int));
            }
        }
    }
}

void deleteArrays(int *** arr){
    for (int i = 0; i < initial_capacity; ++i) {
        for (int j = 0; j < initial_capacity; ++j) {
            for (int k = 0; k < current_count; ++k) {
                arr[i][j][k] = NULL;
            }

        }
    }
    printf("Releasing allocated arrays 1\n");

    for (int i = 0; i < initial_capacity; ++i) {
        for (int j = 0; j < initial_capacity; ++j) {
            arr[i][j] = (int*) realloc(arr[i][j],sizeof(int));
            free(arr[i][j]);
        }
    }
    printf("Releasing allocated arrays 2\n");

    for (int i = 0;  i < initial_capacity; ++i) {
        free(arr[i]);
    }
    printf("Releasing allocated arrays 3\n");

    free(arr);
}


void printArrays(int *** arr){
    for (int i = 0; i < 3; ++i) {
        printf("Array[%d]\n", i);
        for (int j = 0; j < 3; ++j) {
            printf("Array[%d][%d]\nElements: ", i, j);
            for (int k = 0; k < current_count; ++k) {
                printf(" %d", arr[i][j][k]);
            }
            printf("\n");
        }
    }
    printf("\n");
}

int main() {
    int *** generated= initializeArray();
    int count  = 0;
    while (count < 21){
        if(count % 3 == 0) printArrays(generated);
        //verify
        resizeArray(generated);
        generated[0][0][current_count] = rand();
        generated[0][1][current_count] = rand();
        generated[0][2][current_count] = rand();
        generated[1][0][current_count] = rand();
        generated[1][1][current_count] = rand();
        generated[1][2][current_count] = rand();
        generated[2][0][current_count] = rand();
        generated[2][1][current_count] = rand();
        generated[2][2][current_count] = rand();

        current_count++;
        count++;
    }
    /* some operation with data collected */
    deleteArrays(generated);
    printf("Finished deleting dynamic arrays");
    return 0;
}

我试图生成一个三元组,以便在最后一个子集中存储相同数量的信息,同时它的大小和总量不断增加。但是,为了完成进程的动态方面而删除数组的过程总是导致 Process finished with exit code -1073740940 (0xC0000374),这是一个堆损坏错误。我对此不是非常熟悉,对此的任何反馈都会有所帮助。

【问题讨论】:

  • 您是否尝试添加调试语句来打印每个已分配/重新分配/删除的数组的原始指针?基于此,您应该能够检测到任何错误的删除。如果一切正常,请使用静态内存分析工具来查找内存损坏。
  • 不要同时询问 C 和 C++,除非涉及语言之间的差异或交互的问题。由于代码中有 #include 语句在 C 中不起作用,我将删除 C 标记。
  • @SamVarshavchik 我已经查看了一些可能的语句,但通常我设法使用的唯一语句是引用地址的第一项,并且在所有情况下它都会返回一个有效元素。不知道如何在剩余的分配空间中进行验证
  • 真的有必要拥有一个包含 3 个不同 calloc 调用的 3 维数组吗?是否有充分的理由不只使用一维数组而用索引移位来完成其余部分?有时,拥有一大块分配会让你的生活变得更加轻松。此外,您还可以获得缓存局部性的一些好处,具体取决于微处理器:)
  • @hakononakani 这是一个我不知道的概念。通常我只以迭代顺序管理 n 数组。我会调查的!

标签: c++ arrays memory free


【解决方案1】:

例程resizeArray 在其内部循环的每次迭代中将current_capacitycurrent_capacity*=2; 翻倍。第一次调用它时,这导致arr[0][0] 被设置为指向内存为 6 int,而循环继续并最终将current_capacity 设置为 1536。对于程序执行的其余部分,resizeArray 从不分配更多内存,因为它相对于current_capacity 的阈值从未达到。

同时,main 例程继续向generated[0][0] 写入越来越多的元素,将current_count 增加到 20,因此写入超出了分配内存的范围。

可以通过将current_capacity*=2; 移出循环,将其移至if(percentage &gt;= 0.5) 的“then”块内来修复此错误。

还要注意,将多维数组实现为指针到指针或指针到指针到指针的技术在时间和空间上效率低下。 “指针追逐”不利于处理器推测性执行指令。对于固定大小的多维数组,这不用于生产质量代码。在这种需要变量最后一维的情况下,选择不太明确,但使用一个连续的内存分配并使用索引算法来计算数组中的位置而不是指针查找仍然可能更可取。 (C 使可变长度数组变得相当简单,尽管对它们的支持是可选的。C++ 实现可以提供可变长度数组作为扩展,但必要的算术并不难,可以通过辅助函数或类来完成。)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-11-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-16
    相关资源
    最近更新 更多