在C ++中分配3D数组的最惯用的方法是什么?

时间:2019-11-20 20:20:48

标签: c++ arrays

我有以下代码来分配3d数组:


int ***allocate3DArray(int y, int x, int r) {
    int ***array = (int ***) malloc(sizeof(int **) * y);
    for (int i = 0; i < y; i++) {
        array[i] = (int **) malloc(sizeof(int *) * x);
        for (int j = 0; j < x; j++) {
            array[i][j] = (int *) malloc(sizeof(int) * r);
            for (int k = 0; k < r; k++) {
                array[i][j][k] = 0;
            }
        }
    }
    return array;

}


void free3d(int ***arr, int y, int x, int r) {
    for (int i = 0; i < y; i++) {
        for (int j = 0; j < x; j++) {
            free(arr[i][j]);
        }
        free(arr[i]);

    }
    free(arr);

}

这似乎有些笨拙,如果我的malloc失败,则很难进行错误处理。

也就是说,这非常符合人体工程学,因为我可以像这样简单地访问一个元素:int a = arr[x][y][z]

初始化具有相同人体工程学灵活性并同时减轻上述缺点的3d数组的最佳方法是什么?

我尝试过:

    std::array < std::array < std::array < int, radius >, image.cols >, image.rows > houghSpace;

但我遇到了错误:

 error: non-type template argument is not a constant expression
    std::array < std::array < std::array < int, radius >, image.cols >, image.rows > houghSpace;
                                                ^~~~~~
sobel.cpp:117:49: note: initializer of 'radius' is not a constant expression
sobel.cpp:116:15: note: declared here
    const int radius = image.rows / 2;
              ^
sobel.cpp:117:71: error: expected a type
    std::array < std::array < std::array < int, radius >, image.cols >, image.rows > houghSpace;
                                                                      ^
sobel.cpp:117:86: error: C++ requires a type specifier for all declarations
    std::array < std::array < std::array < int, radius >, image.cols >, image.rows > houghSpace;
                                                                                     ^

2 个答案:

答案 0 :(得分:2)

您想要一个具有长方体形状的3维数组。您当前拥有的是一个锯齿状的数组。每个通道可以有独立的大小,并且可以单独分配。这会产生3(4)个问题:

  1. 分配数量为x * y + 1
  2. 读取任何元素都需要3次间接内存加载。
  3. 由于需要保留指向每个分配区域的指针,因此使用的存储量超出了需要。
  4. 您的代码还需要手动处理内存

出于相同的原因,使用向量的解决方案也很糟糕。它只能解决一个问题-手动分配和解除分配。否则会变得更糟,因为它会存储更多的冗余数据。

您想要的是抽象一个连续的内存范围,以便可以将其解释为3d数组。

#include <iostream>
#include <memory>
#include <cstdint>

template <typename T>
struct Array3
{
    Array3(size_t w, size_t h, size_t d) :
        m_data(std::make_unique<T[]>(w*h*d)),
        m_width(w),
        m_height(h),
        m_depth(d)
    {
    }

    T& operator()(size_t x, size_t y, size_t z)
    {
        return m_data[(x * m_height + y) * m_depth + z];
    }

    const T& operator()(size_t x, size_t y, size_t z) const
    {
        return m_data[(x * m_height + y) * m_depth + z];
    }

    size_t width() const
    {
        return m_width;
    }

    size_t height() const
    {
        return m_height;
    }

    size_t depth() const
    {
        return m_depth;
    }

    T* data()
    {
        return m_data.get();
    }

    const T* data() const
    {
        return m_data.get();
    }

private:
    std::unique_ptr<T[]> m_data;
    std::size_t m_width;
    std::size_t m_height;
    std::size_t m_depth;
};


int main()
{
    Array3<int> a(10, 20, 30);
    a(5, 10, 15) = 123;
    std::cout << a(5, 10, 15);
}

使用操作符()而不是[]进行访问。可以使用[]完成,但需要更多样板代码和代理对象。

答案 1 :(得分:0)

一些有关C ++中数组的强烈建议

  • 您不得在C ++中使用malloc和free
  • 您甚至不应再使用NEW和DELETE
  • 您不应从不将原始指针用于拥有的内存。请改用std::unique_ptrstd::shared_ptr

因此,切勿使用上述功能(allocate3DArray,free3d)

好的。因此,现在我们要切换到std::array,您想知道错误消息。如您的示例所示,它们非常清晰。 std::array的大小为静态。它不是动态的。因此,您需要提供一个编译时间常数来定义大小。

您要寻找的是std::vector。它是动态的,可以增加大小,还具有索引运算符。

它可以不受限制地与索引运算符[]一起使用。

请参见以下示例

#include <iostream>
#include <iterator>
#include <vector>

int main()
{
    // Dimensions for the 3 dimensional vector
    size_t xSize{3};
    size_t ySize{4};
    size_t zSize{5};
    int initialValue{0};

    // Define 3 dimensional vector and initialize it.
    std::vector<std::vector<std::vector<int>>> array3d(xSize, std::vector<std::vector<int>>(ySize, std::vector<int>(zSize,initialValue)));

    array3d[1][2][3] = 42;

    std::cout << "Result: " << array3d[1][2][3] << "\n";

    return 0;
}