【问题标题】:C++ Properly deallocate multidimensional array with underlying contiguous memoryC++ 使用底层连续内存正确释放多维数组
【发布时间】:2019-03-31 17:59:23
【问题描述】:

我有一个为 3d 数组分配内存的函数。目标是保证内存是连续的,同时又具有a[k][j][i]语法的便利性:

double *** allocate_3d(const int& sz, const int& sy, const int& sx){
    double * aMem = new double[sz*sy*sx];
    double *** array = new double**[sz];
    for(int k=0; k<sz; k++){
        array[k] = new double*[sy];
        for(int j=0; j<sy; j++){
            array[k][j]= aMem + k*sy*sx + j*sx;
        }
    }
    return array;
}

假设我这样调用函数

x   = allocate_3d(wdz,wdy,wdx);

如何正确释放 x?我尝试了以下方法:

void delete_3d(double *** array, const int& sz, const int& sy, const int& sx){
    for(int k=0; k<sz; k++){    
        for(int j=0; j<sy; j++){
            delete[] array[k][j];
        }
        delete[] array[k];
    }
    delete[] array;
}

但运行 Valgrind 会报错,似乎表明内存没有正确释放。

【问题讨论】:

  • 避免整个头痛,并使用std::vector 为您分配和正确释放所有内存。上面写的任何内容都不需要明确的newdelete。矢量将为您做一切。这就是向量的用途。
  • 我可能是错的,但如果我使用向量的向量的向量,我认为我无法获得语法a[k][j][i] 并且具有连续的内存。
  • 上面的每个动态分配的对象都可以替换为等效的向量。 aMemarray 都可以只是向量。结束。
  • 一个向量保证连续的内存。
  • @EternusVia array[0][0] 给你aMem

标签: c++ multidimensional-array memory-management new-operator delete-operator


【解决方案1】:

其实应该是这样的:

void delete_3d(double *** array, const int& sz, const int& sy, const int& sx) {
    // first, restore the pointer to the actual aMem
    double * aMem = array[0][0];
    // only one dimension was allocated in the loop,
    // so only one loop should be deallocating things
    for(int k = 0; k < sz; k++) {
        delete [] array[k];
    }
    delete[] array;
    delete[] aMem;
}


更好的解决方案

包装std::vector 以获得:连续内存和相当简单的访问语法,并且作为奖励没有额外的数组,这对内存、性能和维护更好:

class Array3d {
public:
    Array3d(size_t sx, size_t sy, size_t sz)
        : m_sx(sx), m_sy(sy) {
        m_array.resize(sx * sy * sz);
    }

    // Can't overload operator[] with more that one parameter
    // so we'll have to do with operator()
    double &operator()(size_t x, size_t y, size_t z) {
        size_t index = x * m_sx * m_sy + y * m_sy + z;
        return m_array[index];
    }

private:
    size_t m_sx, m_sy;
    std::vector<double> m_array;
};

使用示例:

Array3d array(3, 3, 3);
array(0, 1, 2) = 3.14;

【讨论】:

  • 感谢您回答我的问题。
  • @EternusVia,还请考虑我添加的替代解决方案。
  • 感谢您的补充意见。请问使用class方法在哪些方面性能比较好?
  • @EternusVia,如果定义在同一个翻译单元中,类方法几乎肯定会被编译器内联,因此不会有任何开销。另一方面,数组的层次结构在每个级别上增加了额外的间接,CPU“不喜欢”间接,因为它不利于缓存性能,而且您必须为每个元素访问访问多个单独的数组,这对缓存也不利,因为它们可以在记忆中“无处不在”。
  • @EternusVia,在任何情况下,所有这些性能考虑都只是理论上的,直到您实际对代码进行基准测试。您应该始终首先衡量性能,然后才在必要时进行优化,否则您只会沉迷于它并无缘无故地使您的代码变得更加复杂。
猜你喜欢
  • 2010-12-16
  • 2014-11-05
  • 1970-01-01
  • 2022-01-06
  • 2013-06-17
  • 1970-01-01
  • 2014-10-03
  • 2016-03-15
  • 2019-07-27
相关资源
最近更新 更多